3. PHP DESIGN PATTERNS
INTRO
▸ Design patterns represent the best practices used by
experienced object-oriented software developers.
▸ Design patterns are solutions to general problems that
software developers faced during software development.
▸ These solutions were obtained by trial and error by
numerous software developers over quite a substantial
period of time.
3
4. PHP DESIGN PATTERNS
USAGE OF DESIGN PATTERNS
▸ Common platform for developers
▸ Design patterns provide a standard terminology and are specific to
particular scenario. For example, a singleton design pattern signifies
use of single object so all developers familiar with single design
pattern will make use of single object and they can tell each other
that program is following a singleton pattern.
▸ Best Practices
▸ Design patterns have been evolved over a long period of time and
they provide best solutions to certain problems faced during
software development. Learning these patterns helps un-
experienced developers to learn software design in an easy and
faster way.
4
5. PHP DESIGN PATTERNS
TYPES OF DESIGN PATTERNS
▸ Creational Patterns
▸ These design patterns provides way to create objects while hiding the
creation logic, rather than instantiating objects directly using new operator.
This gives program more flexibility in deciding which objects need to be
created for a given use case.
▸ Structural Patterns
▸ These design patterns concern class and object composition. Concept of
inheritance is used to compose interfaces and define ways to compose
objects to obtain new functionalities.
▸ Behavioral Patterns
▸ These design patterns are specifically concerned with communication
between objects.
5
7. PHP DESIGN PATTERNS
FACTORY
▸ In Factory pattern, we create object without exposing the
creation logic to the client and refer to newly created
object using a common interface.
▸ Problem:
▸ A framework needs to standardize the architectural
model for a range of applications, but allow for
individual applications to define their own domain
objects and provide for their instantiation.
7
8. PHP DESIGN PATTERNS
FACTORY
<?php
class Automobile
{
private $vehicleMake;
private $vehicleModel;
public function __construct($make, $model)
{
$this->vehicleMake = $make;
$this->vehicleModel = $model;
}
public function getMakeAndModel()
{
return $this->vehicleMake . ' ' . $this->vehicleModel;
}
}
class AutomobileFactory
{
public static function create($make, $model)
{
return new Automobile($make, $model);
}
}
// have the factory create the Automobile object
$Aventador = AutomobileFactory::create('Lomborghini', 'Aventador');
print_r($Aventador->getMakeAndModel()); // outputs "Lomborghinni Aventador"
8
9. PHP DESIGN PATTERNS
PROTOTYPE
▸ This pattern involves implementing a prototype interface which tells
to create a clone of the current object.
▸ This pattern is used when creation of object directly is costly. For
example, a object is to be created after a costly database operation.
▸ We can cache the object, returns its clone on next request and
update the database as as and when needed thus reducing
database calls.
▸ Problem
▸ Application "hard wires" the class of object to create in each
"new" expression.
9
10. PHP DESIGN PATTERNS
PROTOTYPE
<?php
class SubObject
{
static $instances = 0;
public $instance;
public function __construct() {
$this->instance = ++self::$instances;
}
public function __clone() {
$this->instance = ++self::$instances;
}
}
class MyCloneable
{
public $object1;
public $object2;
function __clone() {
// Force a copy of this->object, otherwise it will point to same object.
$this->object1 = clone $this->object1;
}
}
$obj = new MyCloneable();
$obj->object1 = new SubObject();
$obj->object2 = new SubObject();
$obj2 = clone $obj;
print("Original Object:n");
print_r($obj);
print("Cloned Object:n");
print_r($obj2);
10
11. PHP DESIGN PATTERNS
SINGLETON
▸ This pattern involves a single class which is responsible to
create an object while making sure that only single object
gets created.
▸ This class provides a way to access its only object which can
be accessed directly without need to instantiate the object of
the class.
▸ Problem
▸ Application needs one, and only one, instance of an object.
Additionally, lazy initialization and global access are
necessary.
11
12. PHP DESIGN PATTERNS
SINGLETON
<?php
class Singleton
{
private static $instance;
/* Returns the *Singleton* instance of this class. */
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
/* Protected constructor to prevent creating a new instance of the Singleton via the `new` operator from
outside of this class. */
protected function __construct() { }
/* Private clone method to prevent cloning of the instance of the instance. */
private function __clone() { }
/* Private unserialize method to prevent unserializing of the Singleton instance. */
private function __wakeup() { }
}
class SingletonChild extends Singleton
{
}
$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance()); // bool(true)
$anotherObj = SingletonChild::getInstance();
var_dump($anotherObj === Singleton::getInstance()); // bool(false)
var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)
12
14. PHP DESIGN PATTERNS
ADAPTER
▸ Adapter pattern works as a bridge between two incompatible interfaces.
▸ This pattern involves a single class which is responsible to join
functionalities of independent or incompatible interfaces.
▸ A real life example could be a case of card reader which acts as an adapter
between memory card and a laptop. You plugin the memory card into card
reader and card reader into the laptop so that memory card can be read via
laptop.
▸ Problem
▸ An "off the shelf" component offers compelling functionality that you
would like to reuse, but its "view of the world" is not compatible with the
philosophy and architecture of the system currently being developed.
14
15. PHP DESIGN PATTERNS
ADAPTER
<?php
class SimpleBook {
private $author;
private $title;
function __construct($author_in, $title_in) {
$this->author = $author_in;
$this->title = $title_in;
}
function getAuthor() {
return $this->author;
}
function getTitle() {
return $this->title;
}
}
class BookAdapter {
private $book;
function __construct(SimpleBook $book_in) {
$this->book = $book_in;
}
function getAuthorAndTitle() {
return $this->book->getTitle().' by '.$this->book->getAuthor();
}
}
// client
print('BEGIN TESTING ADAPTER PATTERN');
$book = new SimpleBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns");
$bookAdapter = new BookAdapter($book);
print('Author and Title: '.$bookAdapter->getAuthorAndTitle());
print('END TESTING ADAPTER PATTERN');
15
16. PHP DESIGN PATTERNS
DECORATOR
▸ Decorator pattern allows a user to add new functionality to
an existing object without altering its structure.
▸ This pattern creates a decorator class which wraps the
original class and provides additional functionality
keeping class methods signature intact.
▸ Problem
▸ You want to add behavior or state to individual objects
at run-time. Inheritance is not feasible because it is
static and applies to an entire class.
16
17. PHP DESIGN PATTERNS
DECORATOR
<?php
class Book {
private $author;
private $title;
function __construct($title_in, $author_in) {
$this->author = $author_in;
$this->title = $title_in;
}
function getAuthor() {
return $this->author;
}
function getTitle() {
return $this->title;
}
function getAuthorAndTitle() {
return $this->getTitle().' by '.$this->getAuthor();
}
}
class BookTitleDecorator {
protected $book;
protected $title;
public function __construct(Book $book_in) {
$this->book = $book_in;
$this->resetTitle();
}
//doing this so original object is not altered
function resetTitle() {
$this->title = $this->book->getTitle();
}
function showTitle() {
return $this->title;
}
}
17
class BookTitleExclaimDecorator extends BookTitleDecorator {
private $btd;
public function __construct(BookTitleDecorator $btd_in) {
$this->btd = $btd_in;
}
function exclaimTitle() {
$this->btd->title = "!" . $this->btd->title . "!";
}
}
class BookTitleStarDecorator extends BookTitleDecorator {
private $btd;
public function __construct(BookTitleDecorator $btd_in) {
$this->btd = $btd_in;
}
function starTitle() {
$this->btd->title = Str_replace(" ","*",$this->btd->title);
}
}
$patternBook = new Book('Gamma', 'Design Patterns');
$decorator = new BookTitleDecorator($patternBook);
$starDecorator = new BookTitleStarDecorator($decorator);
$exclaimDecorator = new BookTitleExclaimDecorator($decorator);
print('showing title : ');
print($decorator->showTitle());
print('showing title after two exclaims added : ');
$exclaimDecorator->exclaimTitle();
$exclaimDecorator->exclaimTitle();
print($decorator->showTitle());
print('showing title after star added : ');
$starDecorator->starTitle();
print($decorator->showTitle());
print('showing title after reset: ');
print($decorator->resetTitle());
print($decorator->showTitle());
18. PHP DESIGN PATTERNS
FACADE
▸ Facade pattern hides the complexities of the system and
provides an interface to the client using which the client
can access the system.
▸ This pattern involves a single class which provides
simplified methods required by client and delegates calls
to methods of existing system classes.
18
19. PHP DESIGN PATTERNS
FACADE
<?php
class Book {
private $author;
private $title;
function __construct($title_in, $author_in) {
$this->author = $author_in;
$this->title = $title_in;
}
function getAuthor() {
return $this->author;
}
function getTitle() {
return $this->title;
}
function getAuthorAndTitle() {
return $this->getTitle()
.' by '.$this->getAuthor();
}
}
class CaseReverseFacade {
public static function reverseStringCase($stringIn) {
$arrayFromString =
ArrayStringFunctions::stringToArray($stringIn);
$reversedCaseArray =
ArrayCaseReverse::reverseCase($arrayFromString);
$reversedCaseString =
ArrayStringFunctions::arrayToString($reversedCaseArray);
return $reversedCaseString;
}
}
19
class ArrayCaseReverse {
private static $uppercase_array =
array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', ‘K'); #...
private static $lowercase_array =
array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', ‘k'); #...
public static function reverseCase($arrayIn) {
$array_out = array();
for ($x = 0; $x < count($arrayIn); $x++) {
if (in_array($arrayIn[$x], self::$uppercase_array)) {
$key = array_search($arrayIn[$x], self::$uppercase_array);
$array_out[$x] = self::$lowercase_array[$key];
} else if (in_array($arrayIn[$x], self::$lowercase_array)) {
$key = array_search($arrayIn[$x], self::$lowercase_array);
$array_out[$x] = self::$uppercase_array[$key];
} else {
$array_out[$x] = $arrayIn[$x];
}
}
return $array_out;
}
}
class ArrayStringFunctions {
public static function arrayToString($arrayIn) {
$string_out = null;
foreach ($arrayIn as $oneChar) {
$string_out .= $oneChar;
}
return $string_out;
}
public static function stringToArray($stringIn) {
return str_split($stringIn);
}
}
$book = new Book('Design Patterns', 'Gamma, Helm, Johnson, and Vlissides');
print('Original book title: '.$book->getTitle());
$bookTitleReversed = CaseReverseFacade::reverseStringCase($book-
>getTitle());
print('Reversed book title: '.$bookTitleReversed);
20. PHP DESIGN PATTERNS
PROXY
▸ In proxy pattern, a class represents functionality of another
class.
▸ In proxy pattern, we create object having original object to
interface its functionality to outer world.
20
21. PHP DESIGN PATTERNS
PROXY
class Book {
private $author;
private $title;
function __construct($title_in, $author_in) {
$this->author = $author_in;
$this->title = $title_in;
}
function getAuthor() {
return $this->author;
}
function getTitle() {
return $this->title;
}
}
21
class BookList {
private $books = array();
private $bookCount = 0;
public function __construct() {
}
public function getBookCount() {
return $this->bookCount;
}
private function setBookCount($newCount) {
$this->bookCount = $newCount;
}
public function getBook($bookNumberToGet) {
if ( (is_numeric($bookNumberToGet)) && ($bookNumberToGet <= $this-
>getBookCount())) {
return $this->books[$bookNumberToGet];
}
return null;
}
public function addBook(Book $book_in) {
$this->setBookCount($this->getBookCount() + 1);
$this->books[$this->getBookCount()] = $book_in;
return $this->getBookCount();
}
public function removeBook(Book $book_in) {
$counter = 0;
while (++$counter <= $this->getBookCount()) {
if ($book_in->getAuthorAndTitle() == $this->books[$counter]-
>getAuthorAndTitle()) {
for ($x = $counter; $x < $this->getBookCount(); $x++) {
$this->books[$x] = $this->books[$x + 1];
}
$this->setBookCount($this->getBookCount() - 1);
}
}
return $this->getBookCount();
}
}
22. PHP DESIGN PATTERNS
PROXY
class ProxyBookList {
private $bookList = NULL;
//bookList is not instantiated at construct time
function __construct() { }
function getBookCount() {
if (NULL == $this->bookList) {
$this->makeBookList();
}
return $this->bookList->getBookCount();
}
function addBook($book) {
if (NULL == $this->bookList) {
$this->makeBookList();
}
return $this->bookList->addBook($book);
}
function getBook($bookNum) {
if (NULL == $this->bookList) {
$this->makeBookList();
}
return $this->bookList->getBook($bookNum);
}
function removeBook($book) {
if (NULL == $this->bookList) {
$this->makeBookList();
}
return $this->bookList->removeBook($book);
}
function makeBookList() { //Create
$this->bookList = new bookList();
}
}
22
$proxyBookList = new ProxyBookList();
$inBook = new Book('PHP for Cats','Larry Truett');
$proxyBookList->addBook($inBook);
print('test 1 - show the book count after a book is added');
print($proxyBookList->getBookCount());
print('test 2 - show the book');
$outBook = $proxyBookList->getBook(1);
print($outBook->getAuthor() . ' by ' . $outBook->getTitle());
$proxyBookList->removeBook($outBook);
print('test 3 - show the book count after a book is removed');
print($proxyBookList->getBookCount());
24. PHP DESIGN PATTERNS
CHAIN OF RESPONSIBILITY
▸ As the name suggests, the chain of responsibility pattern
creates a chain of receiver objects for a request.
▸ In this pattern, normally each receiver contains reference
to another receiver.
▸ If one object cannot handle the request then it passes the
same to the next receiver and so on.
24
25. PHP DESIGN PATTERNS
CHAIN OF RESPONSIBILITY
<?php
abstract class AbstractBookTopic {
abstract function getTopic();
abstract function getTitle();
abstract function setTitle($title_in);
}
class BookTopic extends AbstractBookTopic {
private $topic;
private $title;
function __construct($topic_in) {
$this->topic = $topic_in;
$this->title = NULL;
}
function getTopic() {
return $this->topic;
}
//this is the end of the chain - returns title or says
there is none
function getTitle() {
if (NULL != $this->title) {
return $this->title;
}
return 'there is no title avaialble';
}
function setTitle($title_in) {$this->title =
$title_in;}
}
25
class BookSubTopic extends AbstractBookTopic {
private $topic;
private $parentTopic;
private $title;
function __construct($topic_in, BookTopic $parentTopic_in) {
$this->topic = $topic_in;
$this->parentTopic = $parentTopic_in;
$this->title = NULL;
}
function getTopic() {
return $this->topic;
}
function getParentTopic() {
return $this->parentTopic;
}
function getTitle() {
if (NULL != $this->title) {
return $this->title;
}
return $this->parentTopic->getTitle();
}
function setTitle($title_in) {$this->title = $title_in;}
}
26. PHP DESIGN PATTERNS
CHAIN OF RESPONSIBILITY
class BookSubSubTopic extends AbstractBookTopic {
private $topic;
private $parentTopic;
private $title;
function __construct($topic_in, BookSubTopic
$parentTopic_in) {
$this->topic = $topic_in;
$this->parentTopic = $parentTopic_in;
$this->title = NULL;
}
function getTopic() {
return $this->topic;
}
function getParentTopic() {
return $this->parentTopic;
}
function getTitle() {
if (NULL != $this->title) {
return $this->title;
}
return $this->parentTopic->getTitle();
}
function setTitle($title_in) {$this->title =
$title_in;}
}
26
$bookTopic = new BookTopic("PHP 5");
print("bookTopic before title is set:");
print("topic: " . $bookTopic->getTopic() . " title: " . $bookTopic-
>getTitle());
$bookTopic->setTitle("PHP 5 Recipes by Babin, Good, Kroman, and
Stephens");
print("bookTopic after title is set: ");
print("topic: " . $bookTopic->getTopic() . " title: " . $bookTopic-
>getTitle());
$bookSubTopic = new BookSubTopic("PHP 5 Patterns",$bookTopic);
print("bookSubTopic before title is set: ");
print("topic: " . $bookSubTopic->getTopic(). " title: " .
$bookSubTopic->getTitle());
$bookSubTopic->setTitle("PHP 5 Objects Patterns and Practice by
Zandstra");
print("bookSubTopic after title is set: ");
print("topic: ". $bookSubTopic->getTopic() . " title: ".
$bookSubTopic->getTitle());
$bookSubSubTopic = new BookSubSubTopic("PHP 5 Patterns for Cats",
$bookSubTopic);
print("bookSubSubTopic with no title set: ");
print("topic: " . $bookSubSubTopic->getTopic() . " title: " .
$bookSubSubTopic->getTitle());
$bookSubTopic->setTitle(NULL);
print("bookSubSubTopic with no title for set for bookSubTopic
either:");
print("topic: " . $bookSubSubTopic->getTopic() . " title: " .
$bookSubSubTopic->getTitle());
27. PHP DESIGN PATTERNS
OBSERVER
▸ Observer pattern is used when there is one-to-many
relationship between objects such as if one object is
modified, its depenedent objects are to be notified
automatically.
▸ Observer pattern uses three actor classes: Subject,
Observer and Client.
▸ Subject is an object having methods to attach and detach
observers to a client object. We have created an abstract
class Observer and a concrete class Subject that is
extending class Observer.
27
28. PHP DESIGN PATTERNS
OBSERVER
<?php
abstract class AbstractObserver {
abstract function update(AbstractSubject $subject_in);
}
abstract class AbstractSubject {
abstract function attach(AbstractObserver
$observer_in);
abstract function detach(AbstractObserver
$observer_in);
abstract function notify();
}
28
class PatternObserver extends AbstractObserver {
public function __construct() {
}
public function update(AbstractSubject $subject) {
print('*IN PATTERN OBSERVER - NEW PATTERN GOSSIP ALERT*');
print(' new favorite patterns: '.$subject->getFavorites());
print('*IN PATTERN OBSERVER - PATTERN GOSSIP ALERT OVER*');
}
}
29. PHP DESIGN PATTERNS
OBSERVER
class PatternSubject extends AbstractSubject {
private $favoritePatterns = NULL;
private $observers = array();
function __construct() {
}
function attach(AbstractObserver $observer_in) {
//could also use array_push($this->observers,
$observer_in);
$this->observers[] = $observer_in;
}
function detach(AbstractObserver $observer_in) {
//$key = array_search($observer_in, $this-
>observers);
foreach($this->observers as $okey => $oval) {
if ($oval == $observer_in) {
unset($this->observers[$okey]);
}
}
}
function notify() {
foreach($this->observers as $obs) {
$obs->update($this);
}
}
function updateFavorites($newFavorites) {
$this->favorites = $newFavorites;
$this->notify();
}
function getFavorites() {
return $this->favorites;
}
}
29
$patternGossiper = new PatternSubject();
$patternGossipFan = new PatternObserver();
$patternGossiper->attach($patternGossipFan);
$patternGossiper->updateFavorites('abstract factory, decorator,
visitor');
$patternGossiper->updateFavorites('abstract factory, observer,
decorator’);
$patternGossiper->detach($patternGossipFan);
$patternGossiper->updateFavorites('abstract factory, observer,
paisley');
30. PHP DESIGN PATTERNS
STRATEGY
▸ In Strategy pattern, a class behavior or its algorithm can be
changed at run time.
▸ In Strategy pattern, we create objects which represent various
strategies and a context object whose behavior varies as per its
strategy object.
▸ The strategy object changes the executing algorithm of the
context object.
▸ We are going to create a Strategy interface defining an action and
concrete strategy classes implementing the Strategy interface.
▸ Context is a class which uses a Strategy.
30
31. PHP DESIGN PATTERNS
STRATEGY
<?php
class Book {
private $author;
private $title;
function __construct($title_in, $author_in) {
$this->author = $author_in;
$this->title = $title_in;
}
function getAuthor() {
return $this->author;
}
function getTitle() {
return $this->title;
}
function getAuthorAndTitle() {
return $this->getTitle() . ' by ' . $this-
>getAuthor();
}
}
31
class StrategyContext {
private $strategy = NULL;
//bookList is not instantiated at construct time
public function __construct($strategy_ind_id) {
switch ($strategy_ind_id) {
case "C":
$this->strategy = new StrategyCaps();
break;
case "E":
$this->strategy = new StrategyExclaim();
break;
case "S":
$this->strategy = new StrategyStars();
break;
}
}
public function showBookTitle($book) {
return $this->strategy->showTitle($book);
}
}
interface StrategyInterface {
public function showTitle($book_in);
}
32. PHP DESIGN PATTERNS
STRATEGY
class StrategyCaps implements StrategyInterface {
public function showTitle($book_in) {
$title = $book_in->getTitle();
$this->titleCount++;
return strtoupper ($title);
}
}
class StrategyExclaim implements StrategyInterface {
public function showTitle($book_in) {
$title = $book_in->getTitle();
$this->titleCount++;
return Str_replace(' ','!',$title);
}
}
class StrategyStars implements StrategyInterface {
public function showTitle($book_in) {
$title = $book_in->getTitle();
$this->titleCount++;
return Str_replace(' ','*',$title);
}
}
32
$book = new Book('PHP for Cats','Larry Truett');
$strategyContextC = new StrategyContext('C');
$strategyContextE = new StrategyContext('E');
$strategyContextS = new StrategyContext('S');
print('test 1 - show name context C');
print($strategyContextC->showBookTitle($book));
print('test 2 - show name context E');
print($strategyContextE->showBookTitle($book));
print('test 3 - show name context S');
print($strategyContextS->showBookTitle($book));
33. PHP DESIGN PATTERNS
PHP DESIGN PATTERNS REFERENCES
▸ Design Patterns in PHP
▸ https://github.com/ehsangazar/design-patterns-php
▸ Design Patterns - PHP The Right Way
▸ http://www.phptherightway.com/pages/Design-
Patterns.html
▸ Design Patterns in Java
▸ https://www.tutorialspoint.com/design_pattern/
index.htm
33