Top 5 Design Patterns Used In PHP Applications

Image for post
Image for post

In this article, we will teach about the most common design pattern used in PHP application
Many organizations are keen on hiring PHP developers who can help them build some great applications. When almost 8/10 websites you visit are using PHP in some way or another, it is a great idea to know about the design patterns used to make PHP applications.
Do you know, PHP is used by 78.9% of websites with a server-side language!
Here are the top 5 design patterns used to make PHP applications.

Factory

The factory pattern is ideal when you want to build an object. When making a new object you need to create it and then initialize it. Usually, one needs to perform several steps to apply a certain logic. With all the steps involved, it makes sense to have all the steps at one-place and re-use whenever you need to build a new object in the same way. This is how a factory pattern works.

Let us understand it with a code example.

interface FriendFactoryInterface {public function create() : Friend}

Then we move ahead to implement the factory interface with the following class:

class FriendFactory implements FriendFactoryInterface {    public function create() : Friend {        $friend = new Friend();        // initialize your friend        return $friend;    }}

Pros

  • Easy testing of the seam of an application

Cons

  • Makes code more difficult to read

You can also read: Create a Simple Shopping Cart with PHP and Mysql

Strategy

With the Strategy design pattern, you can hide the implementation details of algorithms needed to perform an operation. Moreover, your clients can choose to have the required algorithm without knowing the actual implementation and applying it to perform the operation.

For example, if you need to transfer the data from a spreadsheet to a doc file.

First, you need to create strategies to read data from the storage of the spreadsheet and the database. You can name the strategy as “Readers.” Next, you need to create strategies to write data to the storage. We can choose to call them “Writers.”

Thus, you now have two readers to read the data from the spreadsheet or the database. Similarly, we will have two writers to write data either into the spreadsheet or into the doc file.

Moreover, the client you will work with will have no idea about their implementations. Thus, you need to define interfaces for your strategies.

Lastly, you need to create the client that will select the strategies and then transfer the data.

Here is how you can execute it:

interface ReaderInterface {public function start() : void;public function read() : array;public function stop() : void;}interface WriterInterface {public function start() : void;public function write(array $data) : void;public function stop() : void;}class DatabaseReader implements ReaderInterface {...}class SpreadsheetReader implements ReaderInterface {...}class CsvWriter implements WriterInterface {...}class JsonWriter implements WriterInterface {...}class Transformer {
...public function transform(string $from, string $to) : void {$reader = $this->findReader($from);$writer = $this->findWriter($to);
$reader->start();$writer->start();try {foreach ($reader->read() as $row) {$writer->write($row);}} finally {$writer->stop();$reader->stop();}}...}

In this code, the transformer (client) is not worried about the implementations with which it works. It only cares about methods declined by our strategy interfaces.

Pros:

  • Prevents the use of conditional statements (switch, if, else)

Cons:

  • Clients must be aware of the existence of different strategies

Adapter

The Adapter design pattern allows you to turn a foreign interface into a common interface. Let’s assume that you get the data from some storage using the following class.

class Storage {private $source;public function __constructor(AdapterInterface $source) {$this->source = $source;}public function getOne(int $id) : ?object {return $this->source->find($id);}public function getAll(array $criteria = []) : Collection {return $this->source->findAll($criteria);}}

The storage doesn’t work directly with the source but works with the adapter of the source. Moreover, the storage doesn’t know anything about the concrete adapters and knows only the adapter interface. Thus, the implementation of the adapter is unknown territory for the storage.

Here’s an example of the adapter interface

interface AdapterInterface {public function find(int $id) : ?object;public function findAll(array $criteria = []) : Collection;}

Now, let’s assume that we use some library to access the MySQL database. The library dictates its own interface and it looks like the following:

$row = $mysql->fetchRow(...);$data = $mysql->fetchAll(...);class MySqlAdapter implements AdapterInterface {...public function find(int $id) : ?object {$data = $this->mysql->fetchRow(['id' => $id]);// some data transformation}public function findAll(array $criteria = []) : Collection {$data = $this->mysql->fetchAll($criteria);// some data transformation}
...}

After that, we can inject it into the Storage just like this:

$storage = new Storage(new MySqlAdapter($mysql));

Later, if you decide to use another library, you only need to create another adapter for that library and then inject the new adapter into the storage. Interestingly, you don’t need to touch a thing within the storage class; such is the prowess of the Adapter design pattern.

Pros:

  • Increased reusability and flexibility

Cons:

  • Prone to over-engineering

At this stage, you can also read: How to generate QR Code using php

Observer

The observer design pattern comes in handy when you need to notify the system about specific events. For example, a need to create an event called “Theater” to show movies to critics. However, you need to send messages on their cell phones. Then, in the middle of the movie, you would want to stop the film for 5 minutes to let the critics have a break. Lastly, after the movie ends, you will need to collect feedback from the critics.

Let’s see how this would look in code:

class Theater {public function present(Movie $movie) : void {$critics = $movie->getCritics();$this->messenger->send($critics, '...');$movie->play();$movie->pause(5);$this->progress->break($critics)$movie->finish();$this->feedback->request($critics);}}

Now, after some time, if you feel that before starting the movie, we also need to turn the lights off. Furthermore, in the interval, you may also want to show advertisements. Moreover, when the movie ends, you will want to start the auto cleaning of the room.

The Observer pattern helps spread the complexity across the system rather than adding more complexity to the theater class.

Here’s how this will look like in action:

class Theater {public function present(Movie $movie) : void {$this->getEventManager()->notify(new Event(Event::START, $movie));$movie->play();$movie->pause(5);$this->getEventManager()->notify(new Event(Event::PAUSE, $movie));$movie->finish();$this->getEventManager()->notify(new Event(Event::END, $movie));}}$theater = new Theater();$theater->getEventManager()->listen(Event::START, new MessagesListener())->listen(Event::START, new LightsListener())->listen(Event::PAUSE, new BreakListener())->listen(Event::PAUSE, new AdvertisementListener())->listen(Event::END, new FeedbackListener())->listen(Event::END, new CleaningListener());$theater->present($movie);

Thus, the Observer design pattern simply notifies the rest of the system about the facts. Moreover, it also becomes easy to add additional complexity. All you need to do is create a new listener and put the required logic there.

Pros:

  • Allows sending data to objects in an efficient manner

Cons:

  • Forced use of inheritance vs. programming to an interface

At this stage, you can also read: 5 Web Design Trends To Try On Your Next Web Design Project

Decorator

The decorator design pattern is used when you wish to adjust the behavior of an object at run-time. Furthermore, it helps reduce the number of classes and reduce redundant inheritances.

Let us understand this with a code example.

interface OpenerInterface {public function open() : void;}class Door implements OpenerInterface {public function open() : void {// opens the door}}class Window implements OpenerInterface {public function open() : void {// opens the window}}
class SmartDoor extends Door {public function open() : void {parent::open();$this->temperature();}}class SmartWindow extends Window {public function open() : void {parent::open();$this->temperature();}}

You have a total of 4 classes. However, with the Decorator pattern, you can solve this problem with 3 classes only.

class SmartOpener implements OpenerInterface  {private $opener;public function __construct(OpenerInterface $opener) {$this->opener = $opener;}public function open() : void {$this->opener->open();$this->temperature();}}$door = new Door();$window = new Window();$smartDoor = new SmartOpener($door);$smartWindow = new SmartOpener($window);

Pros:

  • Flexible alternative to subclassing for extending functionality

Cons:

  • May result in many small objects that can lead to complexity

These are some commonly used design patterns in PHP applications. They help web developers and designers to improve their efficiency and increase productivity.

I hope this article useful and interesting. If so, don’t hesitate to clap and share it on the social networks.

Written by

Discuss desk (www.DiscussDesk.com) is a blogging website with new technology content. Here, Users can read and comment on the latest blog.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store