PHP Tutorial

PHP Flow Control

PHP Functions

PHP String

PHP Array

PHP Date Time

PHP Object Oriented

Regular Expression

PHP Cookie & Session

PHP Error & Exception handling

MySQL in PHP

PHP File Directory

PHP Image Processing

PHP Design Patterns

Design patterns are typical solutions to common problems in software design. They're like templates which can be used in multiple situations and are a very important aspect of software development. Here, we'll look at some common design patterns in PHP:

  • Singleton Pattern: The Singleton pattern is used to restrict an object to a single instance of that object across the application. It's commonly used for logging, driver objects, caching, thread pools, and database connections.
class Singleton {
    private static $instance;

    private function __construct() {
        // private to prevent direct creation of object
    }

    public static function getInstance() {
        if (null === static::$instance) {
            static::$instance = new static();
        }
        
        return static::$instance;
    }
}
  • Factory Pattern: The Factory pattern is a class that has some methods that create and return objects of varying classes/types.
interface Animal {
    public function speak();
}

class Dog implements Animal {
    public function speak() {
        return "Woof!";
    }
}

class Cat implements Animal {
    public function speak() {
        return "Meow!";
    }
}

class AnimalFactory {
    public function createAnimal($type) {
        switch ($type) {
            case 'Dog':
                return new Dog();
            case 'Cat':
                return new Cat();
        }
    }
}

$factory = new AnimalFactory();
$animal = $factory->createAnimal('Dog');
echo $animal->speak();  // Outputs: Woof!
  • Observer Pattern: The Observer pattern allows you to build structures where an object's state change is communicated to all dependent objects, also known as observers. It's a great way to reduce hard-coded object interactions.
class User implements SplSubject {
    private $observers;
    
    public function __construct() {
        $this->observers = new SplObjectStorage();
    }
    
    public function attach(SplObserver $observer) {
        $this->observers->attach($observer);
    }
    
    public function detach(SplObserver $observer) {
        $this->observers->detach($observer);
    }
    
    public function notify() {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
    
    public function changeState() {
        // Change state
        $this->notify();
    }
}

class UserObserver implements SplObserver {
    public function update(SplSubject $subject) {
        echo 'The state of User object has been changed!';
    }
}

$user = new User();
$user->attach(new UserObserver());
$user->changeState();  // Outputs: The state of User object has been changed!
  1. Singleton Pattern:

    • Ensures a class has only one instance and provides a global point of access to it.
    class Singleton {
        private static $instance;
    
        private function __construct() {}
    
        public static function getInstance() {
            if (self::$instance === null) {
                self::$instance = new self();
            }
            return self::$instance;
        }
    }
    
  2. Factory Pattern:

    • Defines an interface for creating an object but lets subclasses alter the type of objects that will be created.
    interface Vehicle {
        public function drive();
    }
    
    class Car implements Vehicle {
        public function drive() {
            echo "Driving a car.";
        }
    }
    
    class Bike implements Vehicle {
        public function drive() {
            echo "Riding a bike.";
        }
    }
    
    class VehicleFactory {
        public function createVehicle($type) {
            switch ($type) {
                case 'car':
                    return new Car();
                case 'bike':
                    return new Bike();
                default:
                    throw new \InvalidArgumentException("Invalid vehicle type");
            }
        }
    }
    

Structural Design Patterns:

  1. Adapter Pattern:
    • Allows the interface of an existing class to be used as another interface.
    interface Target {
        public function request();
    }
    
    class Adaptee {
        public function specificRequest() {
            echo "Specific request.";
        }
    }
    
    class Adapter implements Target {
        private $adaptee;
    
        public function __construct(Adaptee $adaptee) {
            $this->adaptee = $adaptee;
        }
    
        public function request() {
            $this->adaptee->specificRequest();
        }
    }
    

Behavioral Design Patterns:

  1. Observer Pattern:

    • Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified.
    interface Observer {
        public function update($data);
    }
    
    class ConcreteObserver implements Observer {
        public function update($data) {
            echo "Received update: $data";
        }
    }
    
    class Subject {
        private $observers = [];
    
        public function addObserver(Observer $observer) {
            $this->observers[] = $observer;
        }
    
        public function notifyObservers($data) {
            foreach ($this->observers as $observer) {
                $observer->update($data);
            }
        }
    }
    
  2. MVC Design Pattern:

    • Separates an application into three main components: Model, View, and Controller.
    class Model {
        private $data;
    
        public function setData($data) {
            $this->data = $data;
        }
    
        public function getData() {
            return $this->data;
        }
    }
    
    class View {
        public function render(Model $model) {
            echo "View rendering: " . $model->getData();
        }
    }
    
    class Controller {
        private $model;
        private $view;
    
        public function __construct(Model $model, View $view) {
            $this->model = $model;
            $this->view = $view;
        }
    
        public function updateData($data) {
            $this->model->setData($data);
            $this->view->render($this->model);
        }
    }
    
  3. Dependency Injection:

    • Allows the client to provide the dependent object to a component.
    class Logger {
        public function log($message) {
            echo "Logging: $message";
        }
    }
    
    class Service {
        private $logger;
    
        public function __construct(Logger $logger) {
            $this->logger = $logger;
        }
    
        public function doSomething() {
            $this->logger->log("Doing something.");
        }
    }
    
    $logger = new Logger();
    $service = new Service($logger);
    $service->doSomething();