DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • SmartXML: An Alternative to XPath for Complex XML Files
  • Java String: A Complete Guide With Examples
  • Power of PHP Frameworks: Boosting Web Development With PHP Frameworks
  • Generics in Java and Their Implementation

Trending

  • A Modern Stack for Building Scalable Systems
  • Performance Optimization Techniques for Snowflake on AWS
  • Contextual AI Integration for Agile Product Teams
  • Scaling DevOps With NGINX Caching: Reducing Latency and Backend Load
  1. DZone
  2. Coding
  3. Languages
  4. Practical PHP Refactoring: Replace Array with Object

Practical PHP Refactoring: Replace Array with Object

By 
Giorgio Sironi user avatar
Giorgio Sironi
·
Aug. 24, 11 · Interview
Likes (0)
Comment
Save
Tweet
Share
11.2K Views

Join the DZone community and get the full member experience.

Join For Free

This refactoring is a specialization of Replace Data Value with Object: its goal is to replace a scalar or primitive structure (in this case, an ever-present array) with an object where we can host methods that act on those data.

We have already seen a lightweight version of this refactoring in the code sample of that article: this time we go all the way to a real object, which has private fields representing the elements of the array.

Usually the target of the refactoring is an associative array, but it may also be a numeric one, with a limited number of elements.

When to introduce an object where a simple array already works?

A clue that points to the need for this refactoring in numerical arrays is the fact that the elements are not homogeneous: they may be in type (all strings or integers) but not in meaning. For example, if two or them are flipped the array loses meaning or becomes very strange:

array(
    'FirstName LastName',
    'address@example.com'
)

For associative arrays, the refactoring is viable everytime the number of elements is strictly fixed:

array(
    'name' => ...
    'email' => ...
)

Private fields are self-documenting, and they're easier to understand and maintain that the documentation of the keys of an array. Documentation on array structures always gets repeated in docblocks and doesn't have a real place to live in without a class; moreover, it's the death of encapsulation as nothing stops client code (even in the parts that should only pass the array to other methods) from accessing every single element of the array.

And of course, a class is a place where to put methods, while an array cannot host them.

Steps

The technique described by Fowler for this refactoring is composed of many little steps:

  1. create a new class: it should contain only a public field encapsulating a little the array.
  2. Change the client code to use this new class in place of the primitive variable.
  3. In an iterative cycle, add a getter and a setter for each field and change client code. At each step, the relevant tests should be run. The methods should still use internally the elements of the array.
  4. When this phase has been completed, make the array private and see if the code still works.
  5. Add private fields to substitute the elements of the array, and change getters and setters accordingly. This change now ripples only into the source code of the new class.
  6. When you're finished, delete the field storing the array.

Many little steps are often appropriate as the usage of the array spans over dozens of differente classes, and raises the risk of reaching an irreparably broken build.

After you have reached the final state, an object with getters and setters, you can go on and remove methods accordingly for immutability or encapsulation; or move Foreign Methods to the new class now that it has become a first class citizen.

Note that tests may encompass even end-to-end ones if the array was used on a large scale. For example, we replaced arrays with objects in the two upper layers of the application, forcing us to run tests at the end-to-end scale.

Example

In the initial state, a response is created by putting together an array. Client code is omitted for brevity, and only the creation part will be our target.

<?php
class ReplaceArrayWithObjectTest extends PHPUnit_Framework_TestCase
{
    public function testCanDefineAnHttpResponse()
    {
        $response = array(
            'success' => true,
            'content' => '{someJson:"ok"}'
        );
    }
}

The array is moved onto a public field of a new class.

<?php
class ReplaceArrayWithObjectTest extends PHPUnit_Framework_TestCase
{
    public function testCanDefineAnHttpResponse()
    {
        $response = new HttpResponse(array(
            'success' => true,
            'content' => '{someJson:"ok"}'
        ));
    }
}

class HttpResponse
{
    public $data;

    public function __construct(array $data)
    {
        $this->data = $data;
    }
}

We add setters (also getters in case we need them.)

class HttpResponse
{
    public $data;

    public function __construct(array $data)
    {
        $this->data = $data;
    }

    public function setSuccess($boolean)
    {
        $this->data['success'] = $boolean;
    }

    public function setContent($content)
    {
        $this->data['content'] = $content;
    }
}

The array becomes private, to check that only getters, setters and methods are really used externally.

<?php
class ReplaceArrayWithObjectTest extends PHPUnit_Framework_TestCase
{
    public function testCanDefineAnHttpResponse()
    {
        $response = new HttpResponse(array(
            'success' => true,
            'content' => '{someJson:"ok"}'
        ));
        $response->setSuccess(false);
        $response->setContent('{}');
        $this->assertEquals(new HttpResponse(array(
            'success' => false,
            'content' => '{}'
        )), $response);
    }
}

class HttpResponse
{
    private $data;

    public function __construct(array $data)
    {
        $this->setSuccess($data['success']);
        $this->setContent($data['content']);
    }

    public function setSuccess($boolean)
    {
        $this->data['success'] = $boolean;
    }

    public function setContent($content)
    {
        $this->data['content'] = $content;
    }
}

Private fields replace the array elements. We can start move logic into methods on the new class.

class HttpResponse
{
    private $success;
    private $content;

    public function __construct(array $data)
    {
        $this->setSuccess($data['success']);
        $this->setContent($data['content']);
    }

    public function setSuccess($boolean)
    {
        $this->success = $boolean;
    }

    public function setContent($content)
    {
        $this->content = $content;
    }
}
Data structure Object (computer science) PHP

Opinions expressed by DZone contributors are their own.

Related

  • SmartXML: An Alternative to XPath for Complex XML Files
  • Java String: A Complete Guide With Examples
  • Power of PHP Frameworks: Boosting Web Development With PHP Frameworks
  • Generics in Java and Their Implementation

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!