PHP Design Patterns

Chigozie Orunta
9 min readJan 30, 2020

One of the remarkable features of PHP is its ease of use for most beginners.

Its simple syntax and lack of strong typing features makes it extremely attractive to most PHP beginners. Unfortunately because of its simplicity, most PHP developers are often found repeating lines of code for simple tasks that could have been avoided by way of design patterns.

Design patterns represent a coding methodology that helps developers reuse solutions for common reoccurring problems thereby enabling them to develop and scale applications faster. An example of a common reoccurring need is CRUD (Create, Read, Update & Delete) operations.

Let’s take a look at some PHP design patterns:

1) Factory Pattern

As the name implies, the word “factory” suggests a “place where things are created in large quantity”. The idea behind the factory pattern is essentially to help decouple code so that if there’s a need to change or rename code, developers would only have to make changes in one place (factory) instead of having to make changes throughout the code where objects or class instances are created.

Here’s an example:

<?php    class Cat {
public $food;
public function __construct() {
$this->food = 'Milk';
}
}

class Dog {
public $food;
public function __construct() {
$this->food = 'Bone';
}
}
class Horse {
public $food;
public function __construct() {
$this->food = 'Hay';
}
}
class Human {
public $food;
public function __construct() {
$this->food = 'Spaghetti';
}
}
class AnimalFactory {
public $animal;
public function create($string) {
switch($string) {
case 'Cat':
$this->animal = new Cat();
break;
case 'Dog':
$this->animal = new Dog();
break;
case 'Horse':
$this->animal = new Horse();
break;
default:
$this->animal = new Human();
break;
}
return $this->animal;
}
public function __construct() {
}
}
$animalfactory = new AnimalFactory(); //Test Animal Factory
$cat = $animalfactory->create('Cat');
echo $cat->food.'<br/>';
$dog = $animalfactory->create('Dog');
echo $dog->food.'<br/>';
$horse = $animalfactory->create('Horse');
echo $horse->food.'<br/>';
$human = $animalfactory->create('');
echo $human->food.'<br/>';
?>

As you can see above the factory class “AnimalFactory” handles the creation of each animal from the public method “create”. So if you needed to change the “AnimalFactory” class name, you’d only need to change the class name where you instantiated the animal factory class and where you declared it.

2) Adapter Pattern

As the name implies, the “adapter” pattern is used to create a codebase that can adapt to changes made in an external class, library or public API that our code relies on so that whenever changes are made at their end it does not affect or break our code.

This comes in handy as most applications rely on libraries and external APIs whose implementation or public methods may change from time to time.

Here’s an example:

<?php    //Public/External API or Library for LinkedIn class     class LinkedInAPI {
public $id;
public function getLinkedInArticleID($id) {
return time().$id;
}
public function __construct() {
$this->id = time();
}
}
//Implementation in our code $linkedInObj = new LinkedInAPI();
$linkedInArticleID = $linkedInObj->getLinkedInArticleID(47);
echo $linkedInArticleID;
?>

The above implementation returns a UNIX timestamp appended to our ID from the LinkedIn API.

Now assuming LinkedIn decides to change their public method “getLinkedInArticleID” to some other name like “getArticleID”??? Now that would be a problem for our codebase because it means anywhere we have used that method in our code, we would obviously have to start making changes to the new name. This is where the adapter pattern comes in!

The adapter pattern helps us retain our previous name via an interface like so:

<?php    //Public/External API or Library for LinkedIn with new method name     class LinkedInAPI {
public $id;
public function getArticleID($id) {
return time().$id;
}
public function __construct() {
$this->id = time();
}
}
//Interface interface IDAdapter {
public function getLinkedInArticleID($id);
}
//Adapter Class

class LinkedInAdapter implements IDAdapter {
private $linkedInObj;
public function __construct(LinkedInAPI $linkedInObj) {
$this->linkedInObj = $linkedInObj;
}
public function getLinkedInArticleID($id) {
return $this->linkedInObj->getArticleID($id);
}
}
//Implementation (as before, but now using an adapter) in our code $linkedInObj = new LinkedInAdapter(new LinkedInAPI());
$linkedInArticleID = $linkedInObj->getLinkedInArticleID(47);
echo $linkedInArticleID;
?>

As you can see our code base remains the same with the exception of using the Adapter class. The new method “getArticleID” is being called in the public method for the LinkedInAdapter class.

3) Decorator Pattern

As the name implies, the “decorator” pattern is used to decorate an object’s properties or member variables by using optional classes without having to modify the object’s parent class.

The beauty of the decorator pattern lies in the fact that we can add new optional classes that we can use to modify (“decorate”) object properties or create a special type of template for result sets without having to alter the parent classes (especially when they have already been tested as working perfectly).

Here’s a simple example:

<?php    class Users {
public $firstname;
public $lastname;
public function __construct() {
$this->firstname = 'Chigozie';
$this->lastname = 'Orunta';
}
}
$user = new Users();
echo 'Customer: '.$user->firstname.' '.$user->lastname;
?>

The above class simply initializes member variables ($firstname, $lastname) in its constructor for use externally as shown below:

<?php  echo 'Customer: '.$user->firstname.' '.$user->lastname; ?>

The last line of code shows the customer’s full name is printed out on the screen by joining the first name and the lastname. While this looks trivial, the above scenario would be very different if we had multiple places where we have used the above type of template system and we needed to change it to say something like this:

<?php  echo 'Customer: '.$user->lastname.', '.$user->firstname; ?>

One option to solving this problem would be to just add a simple public method to the above users class that would help us get the user’s full name like so:

<?php    class Users {
public $firstname;
public $lastname;
public function __construct() {
$this->firstname = 'Chigozie';
$this->lastname = 'Orunta';
}
public function getUsersFullName() {
return $this->lastname.', '.$this->firstname;
}
}
$user = new Users();
echo 'Customer: '.$user->getUsersFullName();
?>

The above method solves the problem quite easily but ends up modifying the Users class which we may not want! And this is exactly what the Decorator class helps us do. We can create a decorator class that helps us handle the decoration aspects for the user object so that we don’t need to touch its parent class like so:

<?php    class Users {
public $firstname;
public $lastname;
public function __construct() {
$this->firstname = 'Chigozie';
$this->lastname = 'Orunta';
}
}
class UserDecorator {
public $user;
public function __construct(Users $user) {
$this->user = $user;
}
public function getUsersFullName() {
return $this->user->lastname.', '.$this->user->firstname;
}
}
$user = new Users();
$userDecorator = new UserDecorator($user);
echo 'Customer: '.$userDecorator->getUsersFullName();
?>

In this way we do not have to touch our parent class and our decorator class helps us handle the decorative aspects of our template.

Here’s another more advanced example of how we can use the decorator pattern:

<?php    interface Clothes {
public function getPrice();
}
class Shirt implements Clothes {
public function getPrice() {
return 1000;
}
}
abstract class ShirtDecorator implements Clothes {
protected $shirt;
public function __construct(Clothes $clothes) {
$this->shirt = $clothes;
}
abstract function getPrice();
}
class ColouredShirt extends ShirtDecorator {
public function getPrice() {
return $this->shirt->getPrice() + 1500;
}
}
class CappedShirt extends ShirtDecorator {
public function getPrice() {
return $this->shirt->getPrice() + 3000;
}
}
//Print Normal Shirt Price $shirt = new Shirt();
echo 'Normal Shirt:<br/>';
echo $shirt->getPrice().'<br/>';
//Print Coloured Shirt Price
$colouredShirt = new ColouredShirt($shirt);
echo 'Coloured Shirt:<br/>';
echo $colouredShirt->getPrice().'<br/>';
//Print Coloured, Capped Shirt Price
$colouredCappedShirt = new CappedShirt($colouredShirt);
echo 'Coloured Shirt with A Cap:<br/>';
echo $colouredCappedShirt->getPrice().'<br/>';
?>

As you can see we didn’t have to start adding extra methods to the parent class “Shirt”, all we simply did was to create public methods with the specifics for additional pricing and extend the decorator class which implements the interface that has getPrice method tied. In this way, the user can add more optional values as much as they desire.

4) Active Record Pattern

As the name implies, the “Active Record” pattern is used to create objects tightly coupled to the database schema and records of a database. To understand how this works here’s a traditional way of performing a read operation from a MySQL database:

<?php    $conx = mysqli_connect("localhost", "username", "password", "database");
$sql_select = "SELECT * FROM products WHERE id = $id";
$result = mysqli_query($conx, $sql_select);
$record = mysqli_fetch_array($result, MYSQLI_ASSOC);
?>

We can rewrite the above code with a simple OOP approach as shown below:

<?php    class Database {
public $localhost;
public $username;
public $password;
public $database;
public $connection_id;
public function __construct($params) {
$this->localhost = $params['localhost'];
$this->username = $params['username'];
$this->password = $params['password'];
$this->database = $params['database'];
$this->connect();
}
public function connect() {
$this->connection_id = mysqli_connect($this->localhost, $this->username, $this->password, $this->database);
}
}
class Products {
public $id;
public $title;
public $price;
public $weight;
public $description;
public $date;
public $connect;
public function __construct(Database $database) {
$this->connect = $database->connection_id;
}
public function getRecord($id) {
$sql = "SELECT * FROM products WHERE id = $id";
$result = mysqli_query($this->connect, $sql);
$record = mysqli_fetch_array($result, MYSQLI_ASSOC);
//Properties...
$this->id = $record['id'];
$this->title = $record['title'];
$this->price = $record['price'];
$this->weight = $record['weight'];
$this->description = $record['description'];
$this->date = $record['date'];
}
}
?>
?>

With the above rewrite, we can now make use of the Products class to show various properties of a product such as id, title, price, weight and so on.

<?php    $params = array("localhost", "username", "password", "database");
$database = new Database($params);
$products = new Products($databse);
$product = $products->getRecord(1);
echo $product->id;
?>

However, if a change were to occur to the database schema, such change would not be accounted for in our code base with this approach. This is what the ActiveRecord pattern seeks to solve.

Here’s a refactoring of our code in our Products class using the ActiveRecord pattern approach:

<?php    class Database {
public $localhost;
public $username;
public $password;
public $database;
public $connection_id;
public function __construct($params) {
$this->localhost = $params['localhost'];
$this->username = $params['username'];
$this->password = $params['password'];
$this->database = $params['database'];
$this->connect();
}
public function connect() {
$this->connection_id = mysqli_connect($this->localhost, $this->username, $this->password, $this->database);
}
}
class Products {
public $connect;
public function __construct(Database $database) {
$this->connect = $database->connection_id;
}
public function getRecord($id) {
$sql = "SELECT * FROM products WHERE id = $id";
$result = mysqli_query($this->connect, $sql);
$record = mysqli_fetch_array($result, MYSQLI_ASSOC);
//Properties...foreach($record as $key=>$value) {$this->$key = $value;
}
}
}
?>
?>

As you can see in the Products class above, the read public method has dynamically assigned each value from the fetched array into a public member variable using a foreach loop. The beauty of this approach is that if our schema changes, our column is automatically assigned to a property instead of our previous arrangement where we hardcoded each line.

<?php    $params = array("localhost", "username", "password", "database");
$database = new Database($params);
$products = new Products($databse);
$product = $products->getRecord(1);
echo $product->id;
?>

In other words, each record becomes an Active Object.

5) Singleton Pattern

As the name implies, the singleton means “a single existence of a particular class”. This may be hard to understand since the existence of most classes would naturally give birth to the existence of many objects (which are the instances of those classes).

However, this becomes useful when you need to set up only one instance of a class such as “a database connection” class. It wouldn’t make sense to go about creating objects of a database class since we only require a single connection instance.

An example is shown below from a custom framework of mine called elopePHP, notice how I used it here:

Database::getInstance();
/**
* Class Database
*/
class Database {
/**
* Private static variables
*
* @var string
*/private static $localhost;
private static $username;
private static $password;
private static $database;
/**
* Public static variables
*
* @var string
*/public static $connectionID;
public static $connectionErrMsg;
/**
* Constructor
*
* @since 1.0.0
*/public function __construct() {
self::$localhost = '';
self::$username = '';
self::$password = '';
self::$database = '';
self::connect();
}
/**
* Connection method
*
* @access private
* @since 1.0.0
*/private static function connect() {
self::$connectionID = mysqli_connect(self::$localhost, self::$username, self::$password, self::$database);
if(mysqli_connect_errno()) {
self::$connectionErrMsg = "Failed to connect to MySQL: ".mysqli_connect_error();
die();
}
}
/**
* Points the class, singleton.
*
* @access public
* @since 1.0.0
*/public static function getInstance() {
static $instance;
if($instance === null) $instance = new self();
return $instance;
}
}

The instance created here:

Database::getInstance();

Helps establish a connection and stores the various public static messages needed for further query actions in other future model classes.

6) MVC Pattern

This is perhaps the most common design pattern used by many popular PHP frameworks out there. It employs the model-view-controller approach and is the progenitor of the HMVC and MVVM methodologies.

The model stands for the business logic that interacts with your database, the view represents your presentation layer (html) and the controller represents the interaction layer between your view and the model, it is responsible for passing along the information to your model and sending results to the view.

Here’s an example of a simple Students model:

class Students {    protected static $connectionID;
protected $errorMessage;
protected $record;
public function __construct() {
self::$connectionID = Database::$connectionID;
}
public function getRecord($id) {
$sql = "SELECT * FROM students WHERE id = $id";
$result = mysqli_query(self::$connectionID, $sql);
$record = mysqli_fetch_array($result, MYSQLI_ASSOC);
foreach($record as $key=>$value) {
$this->record->$key = $value;
}
return $this->record;
}
}

Hope you found this useful.

--

--