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
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Languages
  4. Practical PHP Refactoring: Self Encapsulate Field

Practical PHP Refactoring: Self Encapsulate Field

Giorgio Sironi user avatar by
Giorgio Sironi
·
Aug. 10, 11 · Interview
Like (0)
Save
Tweet
Share
6.61K Views

Join the DZone community and get the full member experience.

Join For Free

We are entering the data organization refactorings section of Fowler's book: these methods apply to object which maintain state, like entities, records, value objects and parameter objects. Sometimes these objects are persisted, while sometimes they remain transient: the refactoring techniques are equivalent for both cases.

We start with a simple refactoring, Self Encapsulate Field, which introduce a bit of indirection over private fields in a class. This refactoring leads to the usage of getters instead of private fields directly, even in the class's own code. Remember the bidirectionality of refactorings: this step can be performed in reverse for simplification.

Why another abstraction?

The reason to access fields indirectly is that subclasses are then allowed to override the getters. Getters and setters introduced by this refactoring do not need to be public (they should remain at least protected however.)

Remember why getters are introduced over public fields? Not for encapsulation (there is a 1-to-1 correspondence with fields), but to prevent modification and allow substitution with a calculated value in the future without affecting the client code.

In this case, the client code is the class itself: you prevent accidental modification, ensuring an immutable class; you also can substitute the body of getX() with a computed value in the future, or perform the substitution only in some subclasses.

Steps

  1. Introduce a getter (and an optional setter) methods, with protected or public visibility.
  2. Find references to the field, and replace them with calls to getX() or setX().
  3. Run tests at the unit level.

You can do a find/replace operation to ensure the field is not referenced anymore outside of the getter or setter, and the constructor. The constructor may in fact need to perform special initialization, or maybe the only place where to populate the field in absence of a setter.

Example

In the code sample, we start from a Paragraph object with a $class field containing the CSS class to display.

<?php
class SelfEncapsulateField extends PHPUnit_Framework_TestCase
{
    public function testParagraphIsDisplayed()
    {
        $p = new Paragraph('Lorem ipsum', 'important');
        $expected = '<p class="important">Lorem ipsum</p>';
        $this->assertEquals($expected, $p->__toString());
    }
}

class Paragraph
{
    private $text;
    private $class;

    public function __construct($text, $class)
    {
        $this->text = $text;
        $this->class = $class;
    }

    public function __toString()
    {
        return "<p class=\"$this->class\">$this->text</p>";
    }
}

A new requirement is introduced: a fixed class for some kind of paragraphs:

    public function testParagraphIsDisplayedAsAlwaysImportant()
    {
        $this->markTestSkipped();
        $p = new ImportantParagraph('Lorem ipsum');
        $expected = '<p class="important">Lorem ipsum</p>';
        $this->assertEquals($expected, $p->__toString());
    }

The usage of the field in the class is encapsulated by a getter:

class Paragraph
{
    private $text;
    private $class;

    public function __construct($text, $class)
    {
        $this->text = $text;
        $this->class = $class;
    }

    public function __toString()
    {
        return "<p class=\"" . $this->getClass() . "\">$this->text</p>";
    }

    protected function getClass()
    {
        return $this->class;
    }
}

And the subclass can finally be created:

class ImportantParagraph extends Paragraph
{
    /**
     * This constructor is an hack, but at least the Liskov Substitution
     * Principle is respected in the external interface, which only
     * consists of __toString().
     * If we want to improve this constructor, we can extract a common
     * abstract class between Paragraph and ImportantParagraph, so that
     * both can have their own constructors.
     */
    public function __construct($text)
    {
        parent::__construct($text, null);
    }
   
    protected function getClass()
    {
        return 'important';
    }
}
PHP Self (programming language)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Building a Real-Time App With Spring Boot, Cassandra, Pulsar, React, and Hilla
  • gRPC on the Client Side
  • Container Security: Don't Let Your Guard Down
  • Spring Boot, Quarkus, or Micronaut?

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
  • +1 (919) 678-0300

Let's be friends: