in php object oriented programming oop design pattern refactor ~ read.

Write Better OOP Code in PHP

I happened to read one post that I found to be so useful to me and I want to share some opinions of the article. You can find the link here.

It is about how to write a maintainable code in an object oriented way that can embrace changes.

Why do I care about writing maintainable code?

Oh well. Let's say if you are working in any forms of organisation, no matters if it is in schools or companies. There is gonna be someone that needs to read the code you wrote, right? Then if that is the case you should write a maintainable code. Cause people will ask you to change and image a few months later if you want to change the code, you will most certainly be the one who has to change it.

So just image that instead of coding, we are actually writing a book. If we all think about coding a book instead of some letters. Then yes, you should care about how to maintain your code.

As for the following, we will have a look at how to write some maintainable codes in OOP styles in PHP.

This post assumes you have a basic understanding of OOP and PHP.

Cohesion

Cohesion is quite a big topic in OOP. Basically it means that the things that belong together should be kept together; otherwise, they should be moved elsewhere.

Let's have a look at the following code.

<?php  
class NotCohesiveClass {  
    private $firstName;
    private $lastName;
    private $hourlyRate;
    private $hours;

    public function __construct($firstName, $lastName) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    public function getFirstName() {
        return $this->firstName;
    }

    public function getLastName() {
        return $this->lastName;
    }

    public function sethourlyRate($hourlyRate) {
        $this->hourlyRate = $hourlyRate;
    }

    public function setHours($hours) {
        $this->hours = $hours;
    }    

    public function salary() {
        return $this->hourlyRate * $this->hours;
    }
}

As you can see that the above class is not cohesive due to the fact that it has the properties and method that should belong together. And it violates Single Responsibility Principle. So let's remove the unnecessary parts of this class to make it more cohesive.

<?php  
class CohesiveClass {  
    private $firstName;
    private $lastName;

    public function __construct($firstName, $lastName) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    public function getFirstName() {
        return $this->firstName;
    }

    public function getLastName() {
        return $this->lastName;
    }
}

Orthogonality

The term Orthogonality seems a little bit overwhelming at the beginning. But the basic idea is about the isolation or elimination of side effects. A method, class or module that changes the state of other unrelated classes or modules is not orthogonal.

Let's have a look at the following example code.

<?php  
class Person {  
    private $firstName;
    private $lastName;

    public function __construct($firstName, $lastName) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    public function getFirstName() {
        $firstName = $this->firstName

        if ($firstName == 'Well') {
            (new AccessCtrl())->invalidPerson($firstName);
        }

        return $firstName;
    }

    public function getLastName() {
        return $this->lastName;
    }
}

class AccessCtrl {  
    function invalidPerson($name){
        echo $name . 'is not valid!';
    }
}

But if you have a closed look at the above code, it doesn't feel right. Why is that? Why should my Person class checking whether this guy is valid or not? Let's see if we can make it a little bit better by removing the responsibility out of Person class.

<?php  
class Person {  
    private $firstName;
    private $lastName;

    public function __construct($firstName, $lastName) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    public function getFirstName() {        
        return $this->$firstName;
    }

    public function getLastName() {
        return $this->lastName;
    }
}

class AccessCtrl {  
    function checkValid($firstName, $lastName) {
        $firstName = (new Person($firstName, $lastName))->getFirstName();
        if ($firstName == 'Well') {
            $this->invalidPerson($firstName);
        }
    }

    function invalidPerson($name){
        echo $name . 'is not valid!';
    }
}

As you can see the above code, we fetch checkValid method out of Person class cause we think the checkValid method should belong to AccessCtrl instead of Person class. In this case the purpose and intent is clear for the other programmers and make sure our Person class is only deal with the stuff it needs to know.

Dependency and Coupling

In most cases, these two words are interchangeable; but, in some cases, one term is preferred over another. They mean pretty much the same thing that how much this class has to rely on the other to be fully functional.

Let's have a look at the following example.

Coupling in a Field

<?php  
class Cart {

    private $person;

    function __construct() {
        $this->person = new Person("Well", "Lin");
    }

}

As you can see the above code that Cart class depends on Person class in the beginning of the construction of the Cart class.

Coupling by Accessing the Other Class Methods

<?php  
class Cart {

    private $person;

    function __construct() {
        $this->person = new Person("Well", "Lin");
    }

    function printFirstName() {
        echo $this->person->getFirstName();
    }

}

In this case Cart class depends on getFirstName method from Person class.

Coupling by Method Reference

<?php  
class Cart {

    private $person;

    function __construct() {
        $this->person = new Person('Well', 'Lin');
    }

    function printFirstName() {
        echo $this->person->firstName();
    }

    function createAPerson() {
        return new Person('Chandler', 'Bing')
    }

}

As you can see the above code that createAPerson returns an object using Person class which is another way of dependence.

Coupling by Polymorphism

<?php  
class Manager extends Person {

}

As you can see we can use inheritance feature of OOP to enhance the dependence of our Manager class.

Reduce Dependence or Coupling

It is better to reduce the dependence or coupling from other classes. Why is that? Cause how many times you encounter some bugs that you fix it here, and it breaks somewhere? I bet a lot of you. So let's see how can we reduce the dependence and coupling of among our classes?

Reducing Coupling by Dependency Injection

<?php  
class Cart {

    private $person;

    function __construct(Person $person = null) {
        $this->person = $person ? : new Person('Well', 'Lin');
    }

}

By injecting the Person object through Cart's constructor, we reduced Cart's dependency upon the Person class. But this is only half of the solution. let's have a look at a better solution.

Reducing Coupling with Interfaces

<?php  
interface IPerson {  
    function getFirstName();
    function getLastName();
}

class Person implements IPerson {  
    private $firstName;
    private $lastName;

    public function __construct($firstName, $lastName) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    public function getFirstName() {
        return $this->firstName;
    }

    public function getLastName() {
        return $this->lastName;
    }
}

class Cart {

    private $person;

    function __construct(IPerson $person = null) {
        $this->person = $person ? : $this->createAPerson();
    }

    function printFirstName() {
        echo $this->person->firstName();
    }

    function createAPerson() {
        return new Person('Chandler', 'Bing')
    }

}

As you can see the above code that Cart class is not dependent on Person class anymore, instead Cart depends on IPerson interface and Cart doesn't care about what class it is as long as the class is implementing IPerson interface which means as long as the class has the getFirstName() and getLastName methods within the class.

End

Hope you guys can have a better understanding of how to write maintainable code using the techniques above. It can sure make our life and other people's life simpler. As always if you have any comments or opinions please leave it below.

comments powered by Disqus