PHP Self Type Hint

Self Function Parameter

The self type hint refers to the current class not to the instance ie. an object of the same type (the current class or a subclass). Every variable passed must be an instanceof the same class.


function foo(self $bar)		// PHP 5.0+
function foo(self $bar = null)	// PHP 5.1+


class foo { 
	function aMethod(self $obj){
		echo var_dump($obj);	
	}
}
class bar extends foo{}
class baz extends bar{}

$e = new foo();
$f = new bar();
$g = new baz();

$e->aMethod($e); // object(foo)#1 (0) { }
$e->aMethod($f); // object(bar)#2 (0) { }
$e->aMethod($g); // object(baz)#3 (0) { }


Self Return Type

If you use self return type it doesn’t matter if the method returns a cloned version of the object, (immutable objects). The object that is returned is of the same type as the object on which the method is called. In the example below whatever is returned will be of type Foo.

function foo(): self	// PHP 7.0+
function foo(): ?self	// PHP 7.1+

interface Foo {
    /**
     * @param Bar $bar
     * @return self
     */
    public function setBar(Bar $bar): self;
}

class Foo implements Foo
{
    /**
     * {@inheritdoc} 
     */
    public function setBar(Bar $bar): Foo
    {
        // ...
        return $this;
    }
}


class ClassName
{
    public function foo(): ?self
    {
        return new ClassName();
    }

    public function bar(): ?self
    {
        return null;
    }
}

$instance = new ClassName();
$instance->foo();
$instance->bar();


Law of Demeter in PHP

Principle of Least Knowledge

The Law of Demeter is a design guideline with as goal to create loose coupling between objects. If an object knows too much about another (knowledge how to access the third object from the first object) is considered as bad design, because the object has to unnecessary traverse from top to bottom of the chain to get actual dependencies it needs to work with.

  • A method of an object can call methods of that object
  • A method can call a method of its parameters
  • A method can call a method of any objects created or instantiated by that method
  • A method can call a method of objects that are dependencies of the methods object
  • A method can call a method of a global variable that is accessible by the object of the method

The One Dot Principle Violation

class InvoiceController
{
    public function create(User $user, $invoiceTotal)
    {
        try {
            $user->getAccount()
                ->getBalance()
                ->substractSum($invoiceTotal);
        } catch (Exception $e) {
            // handle expcetion
        }
    }
}

This introduces tight coupling, which we should always be trying to avoid in our codebase. Tight coupling reduces the quality of our application code, making it harder to maintain. When we modify one piece of tightly coupled code, then when need to review and modify all the other members of the tightly coupled relationships.

class InvoiceController 
{
    use App\User;
    use App\Invoice;

    public function __construct(User $user, Invoice $invoice){
        $this->user = $user; 
        $this->invoice = $invoice;
    }

    public function processPayment()
    {
        try {
            $this->user->payInvoice($this->invoice);
            // The other methods getAccount(), getBalance() and substractSum($invoiceTotal)
            // will be handled in there own class/methods NO CHAINING
        } catch(Exception $e) {
            // handle exception
        }
    }
}

The knowledge of the inner process of the invoice payment now is encapsulated in User class. The Law of Demeter gives us a guideline how to achieve loose coupling in our code and helps to properly encapsulate the knowledge of some complicated operations or logic into the places where they should be.

PHP Higher Order Functions

A higher-order function or, a first-class functions, is defined as one that can accept other functions as arguments or return another function. Both are intimately related, as the ability of a language artifact to be passed in as an argument or returned from a functions hinges on it being considered just another object. This also means, of course, that functions can be assigned to variables.

Assigning a function to a variable

$concat2 = function (string $s1, string $s2): string {
    return $s1. ' '. $s2;
};
$concat2('Hello', 'World');  //-> 'Hello World'

This code takes the anonymous function and assigns it to the variable $concat2. Alternatively, you can check for the presence of a function variable using is_callable():

is_callable($concat2) // true

Returned from a function

Functions can also be returned from other functions, ‘notice the : callable type hint. This is an extremely useful technique for creating families of functions. It’s also the main part of implementing argument currying

function concatWith(string $a): callable {
   return function (string $b) use ($a): string {
      return $a . $b;	
   };
}

$helloWith = concatWith('Hello');
$helloWith('World'); //-> 'Hello World'

A callable as a parameter

A php function argument can be a callable variable

// Use case 1
function apply(callable $func, $a, $b) {
   return $func($a, $b);
}

$add = function (float $a, float $b): float {
   return $a + $b;
};

$divide = function (float $a, float $b): float {
   return $a / $b;
};

apply($add, 5, 5); //-> 10
apply($divide, 5, 5); //-> 10	

// Use case 2

function apply(callable $func): callable {
   return function($a, $b) use ($func) {
      return $func($a, $b);
   };
}

PHP Template Method Pattern and Class Hierarchies

You can tell when you are not using class hierarchies when you start duplicating fields and methods. By cutting and pasting methods, if there was a defect in the Person class, there would most likely be a defect in the Employee class as well because the implementation was copied between the two.

class Person
{
    private $name;

    public function setName($name)
    {
        $this->name = $name;
    }
}

class Employee
{
    private $name;

    public function setName($name)
    {
        $this->name = $name;
    }
}

Template Method Pattern

The Template Method Pattern is a behavioral design pattern that allows you to defines a skeleton of an algorithm in a base class and let subclasses override the steps without changing the overall algorithm’s structure. This also leverages inheritance. Inheritance allows functionality to be built up from related classes. Each class provides specialized support that’s specific to a class’s purpose. It’s common that functionality in an object-oriented application is provided by class hierarchies rather than single, unrelated classes.

name = $name;
    }

    /**
    * The optional method should by default do nothing.
    */    
    abstract public function introduceSelf();

}

class Person extends PersonTemplate
{
    public function introduceSelf()
    {
        echo 'I am a...';
    }
}

class Employee extends PersonTemplate
{
    public function introduceSelf()
    {
        echo 'My job is a...';
    }
}

function getWho(PersonTemplate $e){
	$e->introduceSelf();
}
$employee = new Employee();
$person = new Person();

getWho($employee);
getWho($person);

PHP Class Cohesion and Separation of Concerns

Separation of Concerns (SoC)

SoC means that you try to separate objects by what they should be really concerned about and is a design principle that splits an application up into its relevant categories (concerns).

Cohesion

Cohesion is the extent to which proximate procedures are related to one another. Highly cohesive Object oriented designs are focused and organized in related modules. Learning about “concerns” is important in determining how to organize functions and classes to be highly cohesive. If methods and classes are highly cohesive, you are able to easily split off entire groups without affecting the design. Designs with high cohesion offer the opportunity for lower coupling.

When a design has low cohesion, it has classes and methods that are not grouped well. To avoid low cohesion don’t write relatively generic classes AND follow the single responsibility principle.

Low Cohesion


class Utils
{
    public static function formatAddress($formatType, $address1,
        $address2, $city, $state)
    {
        return "some address string";
    }

    public static function formatPersonName($formatType, $givenName,
        $familyName)
    {
        return "some person name";
    }

    public static function parseAddress($formatType, $val)
    {
        // real implementation would set values, etc...
        return new Address();
    }

    public static function parseTelephoneNumber($formatType, $val)
    {
        // real implementation would set values, etc...
        return new TelephoneNumber();
    }
}

High Cohesion


class AddressUtils
{
    public static function formatAddress($formatType, $address1,
        $address2, $city, $state)
    {
        return "some address string";
    }

    public static function parseAddress($formatType, $val)
    {
        // real implementation would set values, etc...
        return new Address();
    }

}

class PersonUtils
{
    public static function formatPersonName($formatType, $givenName,
        $familyName)
    {
        return "some person name";
    }

    public static function parsePersonName($formatType, $val)
    {
        // real implementation would set values, etc...
        return new PersonName();
    }
}

PHP Loose Coupling and Dependency Injection

Dependency Injection is a software design pattern that allows avoiding hard-coding dependencies and makes possible to change the dependencies both at runtime and compile time. Always inject, (pass object as an argument) dependencies into the constructor. Creating instances within the constructor creates a tight coupling between the two classes.

Version 1 is documented, extendable and testable, as the MyService class does not care how the Config object was made, and it can be interchanged with any instance of IConfig and it can be mocked. If we add a new parameter to Config’s constructor, we then have to modify every class where we create a Config object.

Version 2 is highly coupled, and not easily testable.

Version 1

class MyService {
    public function __construct(IConfig $config){
        $this->config = $config;  // 
    } 
}

// If any dependencies change or object is not created, the problems are not brought to the service class object.
$deps = [1,2];
$config = new Config($deps);
$service = new MyService($config);

// ** NOT
$service = new MyService(new Config($deps));

The MyService class does not necessarily need to know about any IConfig implementation, it should be confined to its own functionality only. So writing any Config class code in MyService class doesn’t make it modular. This also defeats the Single responsibility principle.

Version 1 is now:
  • Modular: The Dependency Injection helps create completely self-sufficient classes or modules
  • Testable: It helps write testable code easily
  • Maintainable: Since each class becomes modular, it becomes easier to manage it

Version 2

Now you have just inherited any problems the Config obj might have

class MyService {
    public function __construct(){
        $this->config = new Config();
    } 
}

Using Factories

If there are NO dependencies required, it can be helpful to use a Factory.

class ServiceFactory
{
    private $storage = [];

    public function create( $name )
    {
        if ( false === array_key_exists( $name, $this->storage ))
        {
            $instance = new $name;
            $this->storage[$name] = $instance;
        }

        return $this->storage[$name];
    }

}

PHP Referential Transparency

In functional programs, variables once defined do not change their value throughout the program. Functional programs do not have assignment statements. If we have to store some value, we define new variables instead. This eliminates any chances of side effects because any variable can be replaced with its actual value at any point of execution. State of any variable is constant at any instant.


$value = 12;
$value = $value + 1 // this changes the value assigned to the variable $value.
          // The expression is not referentially transparent. 

$new_value  = $value + 1 // assigns a value to the variable $new_value.
          // The expression is referentially transparent. 

Referentially transparent functions are pure functions with immutable data structures.