PHPBuilder - PHP Design Patterns



RSS Twitter
Articles

PHP Design Patterns

by: Octavia Anghel
|
October 30, 2015

Design patterns offer solutions to common application design problems. In object-oriented programming, design patterns are normally targeted at solving the problems associated with object creation and interaction, rather than the large-scale problems faced by the overall software architecture. They provide generalized solutions in the form of boilerplates that can be applied to real-life problems. Usually design patterns are visualized using a class diagram, showing the behaviors and relations between classes.

 

1. Singleton

One of these patterns is the Singleton design pattern, which is based on the mathematical concept of a singleton (a set with a single element), by restricting the instantiation of a class to one object -- for those who are familiar with design patterns, it can be an interesting fact that the Singleton pattern in itself is an implementation of the Responsibility pattern. Sometimes the Singleton pattern can solve important programming tasks, but only you can decide where and when it fits your needs. As a trend, you should know that the Singleton pattern fits well when you manage a shared resource - a printer, a file manager, a database connection, loggers, and so on - because your application should only have a single instance in order to avoid conflicting request for the same resource and avoid performance issues.

 

Implement a Singleton Class Template

In this section, you will create a PHP singleton class template. This will be a usual PHP class, but a class that has only one instance and provide a global point to access it. Keeping this in mind, you can develop a singleton PHP class by following these bullets:

 

   • Declare a private static member variable for storing the instance of that class - this is the object instance:

 

private static $_instance = null; 

 

   • Lock down the class constructor by declaring it as private - this will make the class externally uninstantiable:

 

private function __construct() { }

 

   • Prevent external instantiation of copies of singleton class - locking down clone and wakeup methods will prevent duplicate objects (clones):

 

public function __clone() {
trigger_error( "Cannot clone instance of Singleton pattern ...", E_USER_ERROR );
}

public function __wakeup() {
trigger_error('Cannot deserialize instance of Singleton pattern ...', E_USER_ERROR );
}

 

   • Declare a public static method that creates a single instance of that class - it checks if already exists an instance, and if it does, then it returns the same instance each time it is called, otherwise it creates an instance, stores it in the static member variable and returns it:

 

public static function getInstance()
{
if( !is_object(self::$_instance) )
//or if( is_null(self::$_instance) ) or if( self::$_instance == null )
self::$_instance = new self;

//or, in PHP 5.3.0
//if (empty(static::$_instance)) {
// $class = get_called_class();
// static::$_instance = new $class;
//}

return self::$_instance;
}

 

Now, the singleton class template is ready, and it looks like this:

 

class SingletonClass
{
//A static member variable representing the class instance
private static $_instance = null;

//Locked down the constructor, therefore the class cannot be externally instantiated
private function __construct() { }

//Prevent any object or instance of that class to be cloned
public function __clone() {
trigger_error( "Cannot clone instance of Singleton pattern ...", E_USER_ERROR );
}

//Prevent any object or instance to be deserialzed
public function __wakeup() {
trigger_error('Cannot deserialize instance of Singleton pattern ...', E_USER_ERROR );
}

//Have a single globally accessible static method
public static function getInstance()
{
if( !is_object(self::$_instance) )
//or if( is_null(self::$_instance) ) or if( self::$_instance == null )
self::$_instance = new self;

//or, in PHP 5.3.0
//if (empty(static::$_instance)) {
// $class = get_called_class();
// static::$_instance = new $class;
//}

return self::$_instance;
}
}

 

For testing your singleton class, you should add a trivial method to it, such as the next one:

 

//The singleton pattern ends here - from this point forward we have the methods of the class

 

//A simple method to echo something

 

public function test()
{
echo "<h2>I'm a method of a singleton class</h2>";
}

 

Now, you can develop a simple test for the singleton class. The important aspect of your test should be focused on trying to create multiple instances of the singleton class:

 

This page tests the SingletonClass class

<?php
include_once('SingletonClass.php');

$instance_1 = SingletonClass::getInstance();
$instance_2 = SingletonClass::getInstance();

echo("First test:");
$instance_1->test();

echo("Second test:");
$instance_2->test();

//try to clone an instance
echo("Try to clone the singleton instance (if you see blank below, then you better check the logs):");
$cloned = clone $instance_1;
$cloned->test();
?> 

 

2. Factory

The Factory design pattern is a creational pattern and one of the most widely used patterns in modern programming languages. The Factory pattern is a design pattern which is used in software development to encapsulate the processes used for creating objects and which allows for the instantiation of objects at runtime, as you will see below in the application of this article. It is called a Factory Pattern because it is responsible for "manufacturing" an object.

 

A factory method has a distinct name. In principle, a factory pattern can be used when: the creation of the object precludes reuse without significantly duplicating code, the creation of the object requires access to information or resources not appropriate to contain within the composing object, the lifetime management of created objects needs to be centralized to ensure consistent behavior.

 

The Factory pattern is commonly used to create objects via:

 

   • factory method pattern: defines a method that creates and returns new objects

 

   • abstract factory pattern: delegates a subclass to create new objects

 

The listing below is a simple example of using the factory pattern in PHP:

 

<?php

//class factory
class CarFactory
{
public static function create($make, $model)
{
return new Car($make, $model);
}
}

//class Car
class Car
{
private $makeCar;
private $carModel;

public function __construct($make, $model)
{
$this->makeCar = $make;
$this->carModel = $model;
}

public function MakeCar()
{
return $this->makeCar;
}

public function CarModel()
{
return $this->carModel;
}
}

//client
$factory = new CarFactory();
$car = $factory->create('Citroen','C4');
print $car->MakeCar().' '.$car->CarModel();
?> 

 

Abstract factory pattern

The abstract factory pattern relies on factories that encapsulate groups of factories and control over how the client accesses them. The factory method pattern is straightforward and useful to implement, but in more complex systems, you need to organize it. This problem leads you to a new pattern called the abstract factory pattern.

 

3. Decorator

The decorator pattern, also known as Wrapper, is a structural design pattern meant to extend the behavior of an object dynamically without inheritance via subclassing and without affecting the behavior of other objects from the same class. In a simple and direct logic, we have an object, and at run-time, we add to it more tasks to accomplish. We can call this object the target-object, and it can provide from a previous decoration. Decorators are used in almost all languages and all platforms, from the UI to the back end. Most frameworks and run times use the decorator pattern to add flexibility and runtime-specific behavior.

 

<?php

class Car
{
private $model;

public function CarModel()
{
return $this->model;
}

public function setModel($model)
{
$this->model = $model;
}

public function printDescription()
{
foreach ($this->CarModel()->getFeatures() as $option=>$description)
{
echo("$option: $description <br />");
}

echo("Final Price: " . $this->CarModel()->getCarPrice());
}
}

interface CarModel
{
function getCarPrice();
function getFeatures();
}

class BasicCarModel implements CarModel
{
public function getCarPrice()
{
return 10000;
}

public function getFeatures()
{
return array(
'security' => 'Manual Locks',
'engine' => '1.6L 150HP Engine',
'transmission' => '5 Speed Manual Transmission'
);
}
}

class LuxuryCarModel implements CarModel
{
private $model;

public function __construct($model)
{
$this->model = $model;
}

public function getCarPrice()
{
$Price = $this->model->getCarPrice();
$Price += 5450;
return $Price;
}

public function getFeatures()
{
$features = $this->model->getFeatures();

$features['Navigation System'] = 'Yes';
$features['Seat Heater'] = 'Yes';
$features['Sunroof'] = 'Yes';
$features['DVD Video System'] = 'Yes';

return $features;
}
}

$car = new Car();

$car_model = new BasicCarModel();

$car_model = new LuxuryCarModel($car_model);

$car->setModel($car_model);

$car->printDescription();

?> 

 

The output is:

 

security: Manual Locks 
engine: 1.6L 150HP Engine 
transmission: 5 Speed Manual Transmission

Navigation System: Yes 
Seat Heater: Yes 
Sunroof: Yes 
DVD Video System: Yes 
Final Price: 15450

 

4. Facade

The Facade design pattern's scope is to simplify a system which is very complex or difficult to understand because the system has a large number of interdependent classes and provides a simpler interface to the client. It usually involves a single wrapper class which contains a set of members required by client. The facade pattern relates to an object which provides a simplified interface to a larger amount of code, like a class library. The facade object can do the following jobs:

 

   • make a software library easier to use

 

   • make the library more readable

 

   • reduce dependencies on outside code on the inner workings of a library

 

   • wrap a poorly designed collection of APIs with a single well-designed API

 

The listing below is a very intuitive example of demonstrating the facade pattern:

 

<?php

class Triangle
{
public function TriangleArea($a, $b)
{
return ($a + $b)/2;
}
}

class Rectangle
{
public function RectangleArea($a, $b)
{
return $a*$b;
}
}

class Circle
{
public function CircleArea($a)
{
return pi()*pow($a,2);
}
}

class Square
{
public function SquareArea($a)
{
return pow($a,2);
}
}


//Client code
//$triangle = new Triangle();
//echo 'Triangle Area = ', $triangle->TriangleArea(42,16), "<br>";
//$rectangle = new Rectangle();
//echo 'Rectangle Area = ', $rectangle->RectangleArea(20, 11), "<br>";
//$circle = new Circle();
//echo 'Circle Area = ', $circle->CircleArea(8),"<br>";
//$square = new Square();
//echo 'Square Area = ', $square->SquareArea(11), "<br>";

class AreaFacade
{
public function __construct(Triangle $triangle,
Rectangle $rectangle,
Circle $circle,
Square $square)
{
$this->_triangle = $triangle;
$this->_rectangle = $rectangle;
$this->_circle = $circle;
$this->_square = $square;
}

public function calculate($area)
{
if (count(explode(' ',$area))== 4) {
list($geometric_shape,$p1,$number,$p2)=explode(' ',$area);}
else{
list($geometric_shape,$p1,$number1,$comma,$number2,$p2)= explode(' ',$area);}

// eliminating switch constructs is not in the intent of this pattern
switch ($geometric_shape) {
case 'triangle':
return $this->_triangle->TriangleArea($number1, $number2);
break;
case 'rectangle':
return $this->_rectangle->RectangleArea($number1, $number2);
break;
case 'circle':
return $this->_circle->CircleArea($number);
break;
case 'square':
return $this->_square->SquareArea($number);
break;
}
}
}

class AreaFactory
{
public function getArea()
{
return new AreaFacade(new triangle(), new rectangle(), new circle(), new square());
}
}

// Facade client code
$AreaFactory = new AreaFactory;
$Area = $AreaFactory->getArea();
echo 'Circle = ', $Area->calculate('circle ( 288 )'), "<br>";
echo 'Square = ', $Area->calculate('square ( 32 )'), "<br>";
echo 'Rectangle = ', $Area->calculate('rectangle ( 14 , 5 )'), "<br>";
echo 'Triangle = ', $Area->calculate('triangle ( 70 , 18 )'), "<br>";

?> 

 

The output is:

 

Circle = 260576.26105935
Square = 1024
Rectangle = 70
Triangle = 44

 

Conclusion

This article has explored some of the most widely used design patterns: singleton, facade. decorator and factory.

 

Comment and Contribute

Your comment has been submitted and is pending approval.

Author:
Octavia Anghel

Comment:



Comment:

(Maximum characters: 1200). You have characters left.