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
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
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
Partner Zones AWS Cloud
by AWS Developer Relations
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
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • DevOps Midwest: A Community Event Full of DevSecOps Best Practices
  • What to Pay Attention to as Automation Upends the Developer Experience
  • Logging Best Practices Revisited [Video]
  • Reactive Programming

Trending

  • DevOps Midwest: A Community Event Full of DevSecOps Best Practices
  • What to Pay Attention to as Automation Upends the Developer Experience
  • Logging Best Practices Revisited [Video]
  • Reactive Programming
  1. DZone
  2. Coding
  3. Languages
  4. Practical PHP Refactoring: Replace Array with Object

Practical PHP Refactoring: Replace Array with Object

Giorgio Sironi user avatar by
Giorgio Sironi
·
Aug. 24, 11 · Interview
Like (0)
Save
Tweet
Share
10.40K 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.

Trending

  • DevOps Midwest: A Community Event Full of DevSecOps Best Practices
  • What to Pay Attention to as Automation Upends the Developer Experience
  • Logging Best Practices Revisited [Video]
  • Reactive Programming

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

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

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: