PHP Design patterns have proven to be extremely useful to developers and is a major problem solver. To write efficient code, developers must follow best practices. PHP Design patterns is an Object-oriented programming (OOP) concept that is now also used in Drupal 8 projects. With Drupal 8 adopting modern PHP and OOP concepts, design patterns can be leveraged for a cleaner and more robust programming.

Design Patterns in PHP

What are Design Patterns in PHP?

In software engineering, a Design Pattern is a general repeatable solution to commonly occurring problem in software Design. Good Object-oriented designs should be reusable, maintainable and extensible and Design Patterns in PHP could be very helpful in doing that. It does not only help in solving problems, it implies an optimal way addressing common challenges.

Benefits of using Design Patterns

Major benefits of design pattern are :

  • PHP Design patters help in solving repetitive problems faced during development
  • Using design patterns in PHP makes more efficient communication between designers 
  • Other developers looking at your code won’t have to struggle to understand as the code is well structured with design patterns
  • Following best practices helps build more robust software
  • It helps make development faster and easier

Widely used Design Patterns in PHP

Design Patterns can be used in various situations to solve similar problems. There are around 23 design patters that can be broadly categorized into three types of design patterns - Creational, Structural and Behavioral patterns.

Creational Patterns: Design patterns that are used in object creation mechanisms, to create objects that can be decoupled from the system that implemented them.

Structural Patterns: This eases the design by identifying simple ways to realize relationships between entities

Behavioral Patterns: They are used to manage relationships, responsibilities, and algorithms between objects

Factory Pattern

A factory pattern is used to build an object. That’s right — build an object and not create an object. When we build the object, we first create it and then initialize it. Usually, it requires to apply certain logic and perform multiple steps. With that, it makes sense to have all that in one place and re-use it whenever you need to have a new object built in the same way. Fundamentally, that’s the use of the factory pattern.
It’s a great idea to have an interface for our factory and have our code reliant on it and not on a concrete factory

interface FamilyFactoryInterface { 
    public function create() : Family 
}

Next, implement factory interface with the following class:

class FamilyFactory implements FamilyFactoryInterface { 

    public function create() : Family { 

        $family = new Family(); 

        // initialize your family 

        return $family;

    }

}

Adapter Pattern

In Adapter Design Pattern, a class transforms the interface of one class to another class.In this example we have a TextBook class that has a getTitle() and getAuthor() methods. The client expects a getTitleAndAuthor() method. To "adapt" SimpleBook for demoAdapter we have an adapter class, BookAdapter, which takes in an instance of TextBook, and uses the TextBook getTitle() and getAuthor() methods in its own getTitleAndAuthor method.

<?php

class TextBook {

    private $title;
    private $author;
    function __construct($title_in, $author_in) {
        $this->title  = $title_in;

        $this->author = $author_in;
    }

    function getTitle() {
        return $this->title;
    }
    function getAuthor() {
        return $this->author;
    }
}

class BookAdapter {
    private $book;
    function __construct(TextBook $book_in) {
        $this->book = $book_in;
    }
    function getTitleAndAuthors() {
        return $this->book->getTitle().' by '.$this->book->getAuthor();
    }
}

  // client

  writeln('BEGIN TESTING ADAPTER PATTERN');
  writeln('');

  $book = new TextBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns");
  $bookAdapter = new BookAdapter($book);
  writeln('Author and Title: '.$bookAdapter->getTitleAndAuthor());
  writeln('');

  writeln('END TESTING ADAPTER PATTERN');

  function writeln($line_in) {
    echo $line_in."<br/>";
  }

?>

Singleton Pattern

In order to limit the instantiation of a class to a single object, a singleton pattern is used. This can be useful when only one object is needed across the system. It makes sense to allow access to only one instance of a certain class while designing web applications. In order to prevent the explicit creation of objects from the class, a private constructor is utilized.

<?php
class Singleton
{
    public static function getInstance()
    {
        static $instance = null;
        if (null === $instance) {
            $instance = new static();
        }
        return $instance;
    }
    protected function __construct()
    {
    }
    private function __clone()
    {
    }
    private function __wakeup()
    {
    }
}
class SingletonChild extends Singleton
{
}
$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance());
$obj2 = SingletonChild::getInstance();
var_dump($obj2 === Singleton::getInstance());
var_dump($obj2 === SingletonChild::getInstance());
?>

Observer Pattern

It is used to alert the rest of the system about particular events in certain places.
Suppose we need to create a Theater to show movies to the critics. We define the class Theater with the current method. Before presenting the movie, we want to send messages to the critics’ cell phones. Then, in the middle of the movie we want to stop the movie for 5 minutes to let the critics have an interval. Finally, after the end of the movie we want to ask the critics to leave their response.
This is how code looks like

class Theater {
 
    public function current(Movie $movie) : void {
     
        $critics = $movie->getCritics();
        $this->message->send($critics, '...');

        $movie->play();

        $movie->pause(5);
        $this->progress->interval($critics)
        $movie->end();

        $this->response->request($critics);
    }
}

Decorator Pattern

It is used when you want to alter the character of an object at run-time, and with that, reduce unnecessary inheritances and the number of classes. Well, it can be explained with examples
Let’s say we have classes Sofa and Bed, and they both implement SleeperInterface.

interface SleeprInterface {
    public function sleep() : void;
}
class Sofa implements SleeperInterface {
    public function sleep() : void {
        // sleeps on sofa
    }
}
class Bed implements SleeperInterface {
    public function sleep() : void {
        // sleeps on bed
    }
}

Both the sofas and the beds have the same behavior to sleep. Now, we need other sofas and beds with additional functionality that will tell the users the sleep tracking when they sleep on the sofas or beds. With inheritance we can solve this problem just like this:

class SmartSofa extends Sofa {
    public function sleep() : void {
        parent::sleep();
        $this->sleepHours();
    }
}
class SmartBed extends Window {
    public function sleep() : void {
        parent::sleep();
        $this->sleepHours();
    }
}

Now we have 4 classes in total. However, we could solve this problem with 3 classes only with the Decorator pattern. Here’s how:

class SmartSleeper implements SleeperInterface  {
   
    private $sleeper;
    public function __construct(SleeperInterface $sleeper) {
        $this->sleeper = $sleeper;
    }
   
    public function sleep() : void {
        $this->sleeper->sleep();
        $this->sleepHours();
    }
}
$sofa = new Sofa();
$bed = new Bed();
$smartSofa = new SmartSleeper($sofa);
$smartBed = new SmartSleeper($bed);

We have introduced a new type of a sleeper that acts like a proxy but with an extra functionality on top of it.
Leveraging Design Patterns in Drupal 8
While there are many design patterns already established within Drupal before Drupal 8, Drupal 8 now consists of a lot of patterns that were previously unavailable. Some of these new patterns completely replace some older ones, while others introduce some new features to Drupal 8.

The design patterns used in Drupal 8 includes:

  • Object-Oriented Programming Pattern (OOP)
  • Dependency Injections
  • Factory Pattern
  • Singleton

OOP is not really a single pattern, but a completely radical way of conceptualizing and structuring codes that goes way beyond just design patterns. It is the basis for a lot of popular software design patterns in use today, including those used in Drupal 8. It was introduced in Drupal 7, but it was not used extensively, and it was not required. The situation in Drupal 8 is now different, it is used widely, and it is required.

Dependency Injection

Dependency Injections is that software design pattern that would allow you to remove hard-coded dependencies and also make it possible to change them either on runtime or at compile time. Drupal 8 introduced the concept of services in order to decouple the reusable functionalities. core.services.yml is an example for dependency injection in Drupal 8

We have already discussed about Factory Pattern and Singleton above

Mohammed FarhazApr 14, 2020