Design Patterns in PHP (PHPCon Italia)

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

3 comments

Comments 1 - 3 of 3 previous next Post a comment

  • + spriebsch Stefan Priebsch 1 month ago
    I disagree with your interpretation of MVC. Model in MVC (slide #38) has nothing to do with storage, it’s about an abstract representation of domain data that should be independent from the data access layer of your application.
  • + Cu7l4ss Cu7l4ss 5 months ago
    Great Slide,
    Very informative,
    Keep up the great work !
    Thanks again !
  • + guest0ba2e0 guest0ba2e0 6 months ago
    it’s really interesting !!
    thanks a lot !
Post a comment
Embed Video
Edit your comment Cancel

17 Favorites & 1 Group

Design Patterns in PHP (PHPCon Italia) - Presentation Transcript

  1. Design Patterns in PHP Simone Carletti, Altura Labs weppos@weppos.net
  2. About me   Technical Manager in Altura Labs   The first Zend Framework Italian contributor   Addicted to Agile Development and Development Best Practices   Passionate about Object Oriented Programming   I love pizza Simone Carletti, Altura Labs
  3. .. and what about you? Simone Carletti, Altura Labs
  4. Hard Coded Actions Global Variables What’s wrong with this code? Nothing… Context and responsibility conflicts …except all! Output mixed with Presentation mixed elaboration with business logic Simone Carletti, Altura Labs
  5. Designing object oriented software is hard, and designing reusable object-oriented software is even harder. Design Patters (GoF) Simone Carletti, Altura Labs
  6. Design Patterns Simone Carletti, Altura Labs
  7. Design Patterns describe simple and elegant solutions to specific problems in object oriented software design. Simone Carletti, Altura Labs
  8. Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. Christopher Alexander Simone Carletti, Altura Labs
  9. Each pattern is a three-part rule, which expresses a relation between a certain context, a problem and a solution. Christopher Alexander Simone Carletti, Altura Labs
  10. The Gang of Four Simone Carletti, Altura Labs
  11. Essential Elements   Pattern name   A descriptive name for the pattern, in a word or two   Problem   Describes the problem the pattern applies to   Solution   Describes the elements and the resources along with their relationship and responsibilities for solving the problem.   This is just an abstract description, the implementation varies according to the programming language   Consequences   Results and trade-off Simone Carletti, Altura Labs
  12. What are Design Patterns   Solution to common development problems   Reusable successful design and architectures   Common language for developers Simone Carletti, Altura Labs
  13. What Design Patterns are not   The panacea for solving all development problems   Ready to use code scripts   Cut & Paste solutions Simone Carletti, Altura Labs
  14. Why Design Patterns?   Help you to reuse successful design and architectures   Help you to choose design alternatives   Help you to solve problems you haven’t seen before   Give a common vocabulary   Let you communicate quickly and unambiguously   Make a system more reusable Simone Carletti, Altura Labs
  15. Design for Changes The key to maximizing reuse lies in anticipating new requirements and changes to existing requirements, and in designing your systems so that they can evolve accordingly. Design Patterns (GoF) Simone Carletti, Altura Labs
  16. Golden Rules 1.  Program to an interface, not an implementation 1.  Some languages takes this rule to the next level with Duck Typing 2.  Favor Object Composition over Inheritance 1.  Black Box approach 3.  Delegate Simone Carletti, Altura Labs
  17. How to Select a Design Pattern   Consider how to design patterns solve design problems   Scan Intent section   Study how patterns interrelate   Study patterns of like purpose   Examine a cause of redesign   Consider what should be variable in your design Simone Carletti, Altura Labs
  18. How to Use a Design Pattern   Read the pattern once through for an overview   Go back and study the Structure, Participants and Collaboration sections   Look at the Sample Code section to see a concrete example of the pattern in code   Choose names for pattern participants that are meaningful in the application context   Define the classes   Define application-specific names for operations in the pattern   Implement the operations to carry out the responsibilities and collaborations in the patterns Simone Carletti, Altura Labs
  19. How to NOT Use a Design Pattern   Don’t try to rewrite your application to fit a Design Pattern, select the best Pattern according to your needs   Don’t use a Design Pattern because it’s cool… use a Pattern because you need it   Don’t copy/paste language-specific Pattern implementations, understand how the Pattern works and how you can implement it in your application Simone Carletti, Altura Labs
  20. A word of warning Ideally, when the appropriate problem comes along, you should trigger the design pattern and your problem is solved. Russ Olsen, Design Patterns in Ruby Simone Carletti, Altura Labs
  21. patterns : oop = notable products : algebra The question isn't whether you'll encounter most patterns but whether you'll recognize them when they cross your path. Will you know how to cleanly solve the problem represented by the pattern, or will you stumble thought several code iterations before you find an acceptable solutions? Ship it! Simone Carletti, Altura Labs
  22. Design for Changes Do you remember? But we careful… Simone Carletti, Altura Labs
  23. Avoid Over-Engineering Simone Carletti, Altura Labs
  24. Avoid Under-Engineering Simone Carletti, Altura Labs
  25. Don’t fall into the “everything is a pattern” trap Simone Carletti, Altura Labs
  26. Frameworks vs Design Patterns   Design patterns are more abstract than frameworks   Design patterns are smaller architectural elements than frameworks   Design patterns are less specialized than frameworks   A typical framework contains several design patterns, but the reverse is never true Simone Carletti, Altura Labs
  27. Helpful Agile methodologies   Refactoring   Do you really need this Pattern now?   You Ain't Gonna Need It   Refactoring to Pattern   Unit Test   Always have a consistent test suite before refactoring your code   Test-Driven Development Simone Carletti, Altura Labs
  28. Design Pattern Classification Simone Carletti, Altura Labs
  29. Design Patterns by Purpose   Creational Patterns   Concern the process of object creation   Structural Patterns   Deal with the composition of object and classes   Behavioral Patterns   Characterize the way in which classes or objects interact   Concurrency Patterns   Architectural Patterns   … Simone Carletti, Altura Labs
  30. Design Patterns by Scope   Class Patterns Deal with relationships between classes and their subclasses. Ex. Factory Method, Adapter, Template method…   Object Patterns Deal with object relationships. The most part of patterns are in the object scope. Ex. Singleton, Adapter, Decorator, Proxy, Iterator, Observer… Simone Carletti, Altura Labs
  31. Design Patterns   Architectural   Behavioral   MVC   Iterator   Observer   Creational   Strategy   Singleton   Template Method   Factory Method   More   Lazy initialization   Registry   Structural   Mock Object   Adapter   Proxy Simone Carletti, Altura Labs
  32. Q&A (part 1/2) Simone Carletti, Altura Labs
  33. Design Patterns in Action Simone Carletti, Altura Labs
  34. Pattern Template   Problem & Solution   Considerations   In pictures   Implementation & Examples   In the Wild   Using and Abusing Simone Carletti, Altura Labs
  35. MVC Simone Carletti, Altura Labs
  36. MVC: problem & solution Problem Solution   You want an efficient design   The MVC pattern decouples solution to split the view from views and models by the business logic of your establishing a subscribe/notify application protocol between them   You want to keep your   A view reflects the state of the application reusable by model splitting the design in multiple   This approach enables you to layers attach multiple view to a model an provide different representations Simone Carletti, Altura Labs
  37. MVC: in pictures http://betterexplained.com/articles/intermediate-rails-understanding-models- views-and-controllers/ Simone Carletti, Altura Labs
  38. MVC: Model, View and Controller   The model is the domain-specific representation of data. It usually consists in a database or some other storage system.   The view renders the model in a form suitable according to the request. This layer is commonly known with the word template.   The controller processes the requests and it’s in charge of querying the model and returning the right template according to the request. Simone Carletti, Altura Labs
  39. MVC: decoupling View and Model XML Feed (X)HTML iPhone $articles $articles $articles Articles Article::find() Simone Carletti, Altura Labs
  40. MVC: in the wild   The most part of PHP web frameworks implement the MVC pattern, including Symfony, Zend Framework, CakePHP…   The most part of modern PHP applications inherit some principles from MVC pattern.   Many applications use a template engine   Many applications separate the model from the view and interact with the database via ORM frameworks Simone Carletti, Altura Labs
  41. MVC: Single Responsibility Principle   Every object should have a single responsibility, and that all its services should be narrowly aligned with that responsibility.   The most frequent error using MVC is to execute operations in the wrong context Simone Carletti, Altura Labs
  42. MVC: find the error (1) class BookController { public function SuggestionsAction() { $firstChoice = Book::findAll( array( 'conditions' => array('name LIKE ?', '%'.$params['query']), 'order' => 'weight DESC' ) ); $secondChoice = Book::findAll( array( 'conditions' => array('name LIKE ?', '%'.$params['query'].'%'), 'order' => 'weight DESC' ) ); $this->choices = array_merge($firstChoice, $secondChoice); $this->render('suggestions'); } } Simone Carletti, Altura Labs
  43. MVC: find the error (1/solution) // BookController represents the Book controller class BookController { public function SuggestionsAction() { $this->choices = Book::findSuggestionsForKeyword($params['query']); $this->render('suggestions'); } } // Book class represent the Book model class Book { public static function findSuggestionsForKeyword($query) { $firstChoice = self::findAll( array( 'conditions' => array('name LIKE ?', '%'.$params['query']), 'order' => 'weight DESC' ) ); $secondChoice = self::findAll( array( 'conditions' => array('name LIKE ?', '%'. $params['query'].'%'), 'order' => 'weight DESC' ) ); return array_merge($firstChoice, $secondChoice); } } Simone Carletti, Altura Labs
  44. MVC: find the error (2) <h2>Available Tickets</h2> <?php $tickets = Ticket::findAll(array('conditions' => array('published' => true))); $available = array(); foreach($tickets as $ticket) { if ($currentUser->isAdmin() == true || $ticket->isPublic()) { $available[] = $ticket; } } ?> <ul> <?php foreach($available as $ticket) { ?> <li><?php echo $ticket->title == '' ? 'This ticket has no title' : $ticket->title . ' ' . $ticket->price; ?></li> <?php } ?> </ul> Simone Carletti, Altura Labs
  45. Controller MVC: find the error (2/solution) // the controller knows about User's ACL // and runs the appropriate query through the model class TicketsController // define formatters in your model { // only when formatters are not tied to public function AvailableAction() // one or more specific views { class Ticket Model if ($currentUser->isAdmin()) { { $tickets = Ticket::findAll(); // ... } else { $tickets = Ticket::findAllPublic(); public function getFormattedTitle() } { $this->ticket = $tickets; return $ticket->title == '' ? } 'This ticket has no title' : } $ticket->title . ''. View $ticket->price; <h2>Available Tickets</h2> } Helper } <ul> <?php foreach($tickets as $ticket) { ?> // or delegate the responsibility to the view using <li> helpers <?php $ticket->getFormattedTitle(); ?> class TicketsHelper </li> { <?php } ?> public static function formatTitle($ticket) </ul> { return $ticket->title == '' ? <!-- or using helpers --> 'This ticket has no title' : $ticket->title . <h2>Available Tickets</h2> ''. $ticket->price; <ul> } <?php foreach($tickets as $ticket) { ?> } <li> <?php TicketsHelper::formatTitle($ticket) ?> </li> <?php } ?> Simone Carletti, Altura Labs </ul>
  46. Singleton The Highlander Simone Carletti, Altura Labs
  47. Singleton: problem & solution Problem Solution   You want a class to have   The Singleton pattern ensures exactly one instance a class has only one instance, and provide a global point to   You want the instance to be access it easily accessible   You don’t want to use global variables Simone Carletti, Altura Labs
  48. Singleton: considerations   Often used for shared objects such as configurations, queues, database connections…   You don’t want the environment to be responsible of class instantiation   You don’t want the environment to be responsible of avoid multiple class instances   The Singleton is often a mixed behavior Simone Carletti, Altura Labs
  49. Singleton: implementation class Singleton
 {
 // holds the singleton instance
 private static $_instance = null;
 // redefined as private to be called only 
 // from within the class scope
 private function __construct()
 {
 }
 // redefined to deny object clones
 public function __clone()
 {
 throw new Exception('You cannot clone Singleton object');
 }
 public function getInstance()
 {
 if (null === self::$_instance) {
 self::$_instance = new Singleton();
 }
 return self::$_instance;
 }
 } Simone Carletti, Altura Labs
  50. Singleton: example class Singleton
 {
 // holds the singleton instance
 private static $_instance = null;
 // redefined as private to be called only 
 // from within the class scope
 private function __construct()
 {
 }
 // redefined to deny object clones
 public function __clone()
 {
 throw new Exception('You cannot clone Singleton object');
 }
 public function getInstance()
 {
 if (null === self::$_instance) {
 self::$_instance = new Singleton();
 }
 return self::$_instance;
 }
 }
 $instance = Singleton::getInstance();
 $instance->doSomething();
 Singleton::getInstance()->doSomething();
 Singleton::getInstance()->doSomething()->thenSomethingElse();
 Simone Carletti, Altura Labs
  51. Singleton: Class as Singleton   You can declare methods as static and use the class as the container for the Singleton functionality   You are sure no one will create additional instances   You can’t take advantage of other patterns, such as Lazy Initialization   You don’t have control over initialization   You don’t have access to the instance context   It’s not thread safe Simone Carletti, Altura Labs
  52. Singleton: Why not using Global Variables?   There’s no way to control the value of a global variable   Doesn’t prevent someone from creating multiple instances   Global variables are unpredictable   Global variables are difficult to debug and test   Global variables are unsecure   Global variable makes the code difficult to read Simone Carletti, Altura Labs
  53. Singleton: in the wild   Pake, the Symfony PHP-make library   Doctrine_Manager, the base component of all Doctrine based projects. It opens and keeps track of all database connections   Many components of the Symfony framework, including   sfContext   sfAutoload   sfCultureInfo   The configuration class ConfigFile in phpMyAdmin Simone Carletti, Altura Labs
  54. Singleton: using & abusing   Before applying a Singleton ask yourself: do I really need a Singleton?   Look at your code, check the number of a class instances   Beware to not spread the Singleton knowledge in classes where you don’t really need to   To all intents and purposes, a Singleton instance is a normal class instance, you can pass it as a parameter Simone Carletti, Altura Labs
  55. Factory Method Simone Carletti, Altura Labs
  56. Factory Method: problem & solution Problem Solution   You want to create an   The Factory Method pattern instance of a class but you defines an interface for don’t know in advance the creating an object, but lets object class you need to use subclasses decide which class to instantiate.   You want to localize the knowledge of which class   The Factory Method defers must be instantiated instantiation Simone Carletti, Altura Labs
  57. Factory Method: considerations   It’s difficult to find in PHP an original implementation of the Factory Method as defined by the GoF   There are different variation to the original Factory Method   The GoF discussed both Factory Method and Abstract Factory Simone Carletti, Altura Labs
  58. Factory Method: example public static function factory($uri = 'http') { // Separate the scheme from the scheme-specific parts $uri = explode(':', $uri, 2); $scheme = strtolower($uri[0]); $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; if (strlen($scheme) === 0) { require_once 'Zend/Uri/Exception.php'; throw new Zend_Uri_Exception('An empty string was supplied for the scheme'); } // Security check: $scheme is used to load a class file, so only alphanumerics are allowed. if (ctype_alnum($scheme) === false) { require_once 'Zend/Uri/Exception.php'; throw new Zend_Uri_Exception('Illegal scheme supplied, only alphanumeric characters are permitted'); } /** * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown. */ switch ($scheme) { /* factory pattern implementation */ } Zend_Loader::loadClass($className); $schemeHandler = new $className($scheme, $schemeSpecific); return $schemeHandler; } Simone Carletti, Altura Labs
  59. Factory Method: example public static function factory($uri = 'http') { // ... switch ($scheme) { case 'http': // Break intentionally omitted case 'https': $className = 'Zend_Uri_Http'; break; case 'mailto': // TODO default: require_once 'Zend/Uri/Exception.php'; throw new Zend_Uri_Exception(\"Scheme \\\"$scheme\\\" is not supported\"); break; } Zend_Loader::loadClass($className); $schemeHandler = new $className($scheme, $schemeSpecific); return $schemeHandler; } Simone Carletti, Altura Labs
  60. Factory Method: in the wild   Zend_Uri::factory() returns the right Zend_Uri subclass according to the type of URI passed as parameter   Zend_Cache::factory() returns the best Zend_Cache engines according to given options and configurations   Doctrine contains several implementation of the Factory pattern. For example Doctrine_Node::factory() return node instance based upon chosen implementation Simone Carletti, Altura Labs
  61. Factory Method: using & abusing   Use the Factory Method only if you really need it   Don’t anticipate future needs, refactoring is usually the right choice   Plans might change and you just spent time building useless, heavy infrastructures   Be Smart! Be Agile! Be Lazy! Simone Carletti, Altura Labs
  62. Lazy Initialization Lazy evaluation Simone Carletti, Altura Labs
  63. Lazy Initialization: problem & solution Problem Solution   You want to delay the creation   The Lazy Initialization pattern of an instance or an delays the creation of an expensive operation until the object or the execution of an first time it is needed expensive process until the first time it is needed   You want the operation to be executed only when and if necessary Simone Carletti, Altura Labs
  64. Lazy Initialization: example class PluginManager { protected $_plugins;
 public function getPlugins() {
 // parse list once only when needed and store it in memory
 if (null === $this->_plugins) {
 $this->_plugins = $this->parsePluginList();
 }
 return $this->parsePluginList();
 }
 public function activate($class) {
 require_once $class; // require the class once 
 $plugin = new $class; // only if and when needed
 $plugin->activate();
 }
 public function deactivate($class) {
 if (!isActive($class)) {
 require_once 'Plugin_Not_Active_Exception.php';
 throw new PluginNotActiveException(\"Plugin $class not active\");
 }
 $plugin = new $class;
 $plugin->deactivate();
 }
 // check whether $class is in getPlugins()
 protected function isActive($class) { /* */ }
 // scans a folder tree looking for plugin files
 // this is a really expensive operation
 protected function parsePluginList() { /* */ }
 }
 Simone Carletti, Altura Labs
  65. Lazy Initialization: in the wild   The most part of Zend_Exception classes in Zend Framework are lazy-loaded   Controller classes in Symfony, Zend Framework and (almost) every PHP Framework are lazy-loaded   Many resources in Xoops, such as the ReplacementArray, are lazy-instantiated   Drupal maintains an internal registry of functions or classes in the system, allowing it to lazy-load code files as needed Simone Carletti, Altura Labs
  66. Adapter Simone Carletti, Altura Labs
  67. Adapter: problem & solution Problem Solution   You want to reuse a library in   The Adapter pattern converts your application but it doesn’t the interface of a class into match your interface another interface clients expect   You want to normalize multiple libraries to use the   Adapter lets classes work same interface together that couldn’t otherwise because of incompatible interfaces Simone Carletti, Altura Labs
  68. Adapter: considerations   Adapter is a common pattern when using third party libraries   If you are developing your own libraries, you might want to avoid adapters and use common habits and guidelines   Often using in cooperation with other patterns, such as the Strategy pattern   Adapt or Modify?   Adapter pattern and Proxy pattern are similar, but they have different intents. Adapter is meant to change the interface of an existing object Simone Carletti, Altura Labs
  69. Adapter: example class MySQL_Connection { public static function connect($host, $user, $pass) { // main connection logic } } class PostgreSQL { public static function do_connect($args = array()) { // main connection logic } } class OracleCoolLibrary { public function __construct($args = array()) { // main connection logic } public function connect() { // main connection logic } } Simone Carletti, Altura Labs
  70. Adapter: example class MySQL_Connection class MySQL_Adapter extends MySQL_Connection { { public static function connect($host, $user, $pass) public static function connect($params) { { // main connection logic $host, $user, $pass = list($params); } parent::connect(array($host, $user, $pass)); } } } class PostgreSQL class PostgreSQL_Adapter extends PostgreSQL { { public static function do_connect($args = array()) public static function connect($params) { { // main connection logic self::do_connect($params); } } } } class OracleCoolLibrary class Oracle_Adapter extends OracleCoolLibrary { { public function __construct($args = array()) public static function connect($params) { { // main connection logic $instance = new OracleCoolLibrary($params); } $instance->connect(); } public function connect() } { // main connection logic } } Simone Carletti, Altura Labs
  71. Adapter: in the wild   Zend_Db and all the database-specific subclasses   Zend_Http_Client provides different adapters for different purposes (including a test adapter)   Doctrine DBAdapter and database-specific subclasses Simone Carletti, Altura Labs
  72. Adapter: using & abusing   Avoid creating adapter of adapters   Go to the main library and build the Adapter at the lowest possible level Simone Carletti, Altura Labs
  73. Proxy Simone Carletti, Altura Labs
  74. Proxy: problem & solution Problem Solution   You need to provide access to   The Proxy pattern provides a an object without exposing the surrogate or placeholder for object directly an other object to control access to it   You want to control access to that object   You want to filter access to that object Simone Carletti, Altura Labs
  75. Proxy: considerations   The Proxy is build around a lie   You might want to expose a similar public API   Remember: composition over inheritance   Duck Typing or Interface   You might want to improve performance for expensive operations Simone Carletti, Altura Labs
  76. Proxy: example // This class represents a simple bank account class Account { protected $balance; public function __construct() { } public function deposit($amount) { $this->balance += (int) $amount; return $this; } public function withdraw($amount) { $this->balance -= (int) $amount; return $this; } public function getBalance() { return $this->balance; } } Simone Carletti, Altura Labs
  77. Proxy: example class AccountProxy $proxy = new AccountProxy(new Account()); { $proxy->deposit(20)->withdraw(5); protected $account; print $proxy->getBalance(); public function __construct($account) { $this->account = $account; return $this; } public function deposit($amount) { $this->account->deposit($amount); return $this; } public function withdraw($amount) { $this->account->withdraw($amount); return $this; } public function getBalance() { return $this->account->getBalance(); } } Simone Carletti, Altura Labs
  78. Proxy: example with Lazy Instantiation pattern class AccountProxy class AccountProxy { { protected $account; protected $account; public function __construct($account) public function deposit($amount) { { $this->account = $account; $this->getAccount()->deposit($amount); return $this; return $this; } } public function deposit($amount) public function withdraw($amount) { { $this->account->deposit($amount); $this->getAccount()->withdraw($amount); return $this; return $this; } } public function withdraw($amount) public function getBalance() { { $this->account->withdraw($amount); return $this->getAccount()->getBalance(); return $this; } } protected function getAccount() public function getBalance() { { if (null === $this->account) { return $this->account->getBalance(); $this->account = new Account(); } } } return $this->account; } } Simone Carletti, Altura Labs
  79. Proxy: Virtual Proxy class AccountProxy class AccountProxy account { { protected $account; protected $account; $args public function deposit($amount) public function __call($name, $args) { { $this->getAccount()->deposit($amount); $account = $this->getAccount(); return $this; if (!is_callable(array(&$account, $name))) { } throw new Exception(\"No method $name\"); __call } public function withdraw($amount) $this{ $value or $params = array(&$account, $name) ; $this->getAccount()->withdraw($amount); $return = call_user_func_array($params, $args); return $this; return $return === $account ? $this : $return; } } public function getBalance() protected function getAccount() { { return $this->getAccount()->getBalance(); if (null === $this->account) { } $this->account = new Account(); } protected function getAccount() return $this->account; { } if (null === $this->account) { } $this->account = new Account(); } return $this->account; } } Simone Carletti, Altura Labs
  80. Proxy: in the wild   PHP 5 SOAP Library has examples of Remote Proxy in the WSDL mechanism   Many classes in Symfony provide proxy methods to shorten the code needed for get/set operations   $request->getParameterHolder()->set('foo', 'bar');   $request->setParameter('foo', 'bar'); Simone Carletti, Altura Labs
  81. Proxy: using & abusing   Don’t forget to redefine special class methods accordingly   __clone   __get   __set   __toString   …   Avoid responsibility-mistakes   Be sure all classes are well documented, especially when using virtual proxies and difficult-to-auto-document features Simone Carletti, Altura Labs
  82. Iterator Simone Carletti, Altura Labs
  83. Iterator: problem & solution Problem Solution   You have a complex   The Iterator pattern provides a aggregate object and you way to access the elements of want to access its elements an aggregate object without working on sequentially without exposing implementation the underlying representation   You want to traverse and manipulate a collection object Simone Carletti, Altura Labs
  84. Iterator: considerations   You might not realize it, but you use the Iterator pattern every day working with Arrays Simone Carletti, Altura Labs
  85. Iterator: example $colors = array('yellow', 'orange', 'green'); foreach($colors as $color) { print \"Current color: $color\\n\"; } $items = array( 'first' => 1, 'second' => 2, 'third' => 3, ); foreach($items as $key => $value) { print \"Value $value for key $key\\n\"; } Simone Carletti, Altura Labs
  86. Iterator: SPL example class Zend_Service_Amazon_ResultSet implements SeekableIterator { /** * A DOMNodeList of <Item> elements */ protected $_results = null; /** * Current index for SeekableIterator */ protected $_currentIndex = 0; /** * Implement SeekableIterator::current() * * @return Zend_Service_Amazon_Item */ public function current() { return new Zend_Service_Amazon_Item($this->_results->item($this->_currentIndex)); } /** * Implement SeekableIterator::key() * * @return int */ public function key() { return $this->_currentIndex; } Simone Carletti, Altura Labs
  87. Iterator: SPL example /** * Implement SeekableIterator::next() */ public function next() { $this->_currentIndex += 1; } /** * Implement SeekableIterator::rewind() */ public function rewind() { $this->_currentIndex = 0; } /** * Implement SeekableIterator::seek() */ public function seek($index) { $indexInt = (int) $index; if ($indexInt >= 0 && (null === $this->_results || $indexInt < $this->_results->length)) { $this->_currentIndex = $indexInt; } else { throw new OutOfBoundsException(\"Illegal index '$index'\"); } } /** * Implement SeekableIterator::valid() */ public function valid() { return null !== $this->_results && $this->_currentIndex < $this->_results->length; } } Simone Carletti, Altura Labs
  88. Iterator: PHP 5 SPL   SPL offers some advanced Iterator algorithms   Iterator   RecursiveIterator   SeekableIterator   ArrayIterato   Don’t forget to have a look at the Countable interface Simone Carletti, Altura Labs
  89. Iterator: in the wild   PHP 5 DirectoryIterator library   Zend_Feed, Zend_Service_Amazon, Zend_Service_Technorati in the Zend Framework Simone Carletti, Altura Labs
  90. Iterator: using & abusing   Limit (or avoid) using iterators for changing internal object status   Don’t fall into the concurrent modification trap!   Be sure you are not altering iterator internal index Simone Carletti, Altura Labs
  91. Observer Simone Carletti, Altura Labs
  92. Observer: OMG! class User { protected $_logger; protected $_username; public function __construct($username, $notifier) { $this->_username = $username; $this->_logger = new Logger(); $this->_notifier = $notifier; } public function setUsername($username) { $this->_username = $username; $this->_logger->debug(\"$username changed username\"); $this->_notifier->userChangedLogin($this); } public function login($password) { // login login $this->_logger->debug(\"$username logged in\"); } } Simone Carletti, Altura Labs
  93. Observer: problem & solution Problem Solution   You want objects to interact   The Observer pattern defines each other without making the dependency between objects classes tightly coupled so that when one object change state, all its   You need to maintain dependents are notified and consistency between related updated automatically objects with data integrity in mind Simone Carletti, Altura Labs
  94. Observer: implementation class Subject {
 protected $_observers = array();
 public function attach($observer)
 {
 $this->_objservers[] = $observer;
 }
 public function detach($observer)
 { 
 $observers = array();
 foreach($this->_observers as $object) {
 if ($object !== $observer) {
 $observers[] = $object;
 }
 }
 $this->_observers = $observers;
 }
 public function notify()
 {
 foreach($this->_observers as $observer) {
 $observer->update($this);
 }
 }
 } Simone Carletti, Altura Labs
  95. Observer: example class User { $user = new User(); $user->attach(new Logger()); protected $_username; $user->attach(Notifier::getInstance()); protected $_observers = array(); $user->setUsername('foobar'); public function attach($observer) { // ... see implementation } public function detach($observer) { // ... see implementation } public function notify() { // ... see implementation } public function setUsername($username) { $this->_username = $username; $this->notify(); } } Simone Carletti, Altura Labs
  96. Observer: PHP 5 SPL   SPL suggests a standard way of implementing the Observer pattern.   interface SplObserver   interface SplSubject   class SplObjectStorage Simone Carletti, Altura Labs
  97. Observer: in the wild   Zend_XmlRpc_Server_Fault in Zend Framework accepts a list of observers and notifies them in case of unexpected behaviors Simone Carletti, Altura Labs
  98. Observer: using & abusing   Don’t notify observers if you don’t need   Consider to add specific notifications if you find yourself calling update() too many times for different kind of notifications   ->update()   ->save()   ->delete()   Be careful to notify observers only when a consistent change is complete.   Remember, your object should provide a way to let observers know what changed Simone Carletti, Altura Labs
  99. Template Method Simone Carletti, Altura Labs
  100. Template Method: problem & solution Problem Solution   You have a complex come   The Template Method pattern that might vary somewhere in describes the skeleton of an the middle algorithm in an operation, deferring some steps to   You want to let subclasses subclasses change part of the abstract class algorithms   Template Method lets subclasses redefine certain   You want to defer to steps of an algorithm without implementations some parts changing the algorithm’s of an algorithms structure Simone Carletti, Altura Labs
  101. Template Method: considerations   Template Method is based on inheritance   Strategy pattern can be considered the composition variant Simone Carletti, Altura Labs
  102. Template Method: implementation abstract class AbstractClass { public final function templateMethod() { print \"AbstractClass::templateMethod()\\n\"; $this->mandatoryMethod(); $this->optionalMethod(); } protected abstract function mandatoryMethod(); $o = new FirstConcreteClass; $o->templateMethod(); protected function optionalMethod() # AbstractClass::templateMethod() { # FirstConcreteClass::mandatoryMethod() print \"AbstractClass::optionalMethod()\\n\"; # AbstractClass::optionalMethod() } } $o = new SecondConcreteClass; $o->templateMethod(); class FirstConcreteClass extends AbstractClass # AbstractClass::templateMethod() { # SecondConcreteClass::mandatoryMethod() protected function mandatoryMethod() { # SecondConcreteClass::optionalMethod() print \"FirstConcreteClass::mandatoryMethod()\\n\"; } } class SecondConcreteClass extends AbstractClass { protected function mandatoryMethod() { print \"SecondConcreteClass::mandatoryMethod()\\n\"; } protected function optionalMethod() { print \"SecondConcreteClass::optionalMethod()\\n\"; } } Simone Carletti, Altura Labs
  103. Template Method: example abstract class Page { protected $_title; protected $_content; public function __construct($title, $content) { $this->_title = $title; $this->_content = (array) $content; } public final function generate() { $this->generateHeader(); $this->generateTitle(); $this->generateBodyHeader(); $this->generateBody(); $this->generateBodyFooter(); $this->generateFooter(); } protected abstract function generateHeader(); protected abstract function generateBodyHeader(); protected abstract function generateBodyFooter(); protected abstract function generateFooter(); protected abstract function generateLine($line); protected function generateTitle() { printf(\"Title: %s\\n\", $this->_title); } protected final function generateBody() { foreach($this->_content as $line) { $this->generateLine($line); } } } Simone Carletti, Altura Labs
  104. Template Method: example class FeedPage extends Page { class HtmlPage extends Page { protected function generateHeader() { protected function generateHeader() { printf(\"<?xml version=\\\"1.0\\\"?>\\n\"); printf(\"<html>\\n\"); printf(\"<rss version=\\\"2.0\\\">\\n\"); } printf(\" <channel>\\n\"); protected function generateTitle() { } printf(\"<head><title>%s</title></head>\\n\", protected function generateTitle() { $this->_title); $title = $this->_title; } printf(\" <title>%s</title>\\n\", $title); protected function generateBodyHeader() { } printf(\"<body>\\n\"); protected function generateBodyHeader() { } } protected function generateBodyFooter() { protected function generateBodyFooter() { printf(\"</body>\\n\"); } } protected function generateFooter() { protected function generateFooter() { printf(\" </rss>\\n\"); printf(\"</html>\\n\\n\"); printf(\"</channel>\\n\\n\"); } } protected function generateLine($line) { protected function generateLine($line) { printf($line); printf(\" <item><title>%s</title></item>\\n\", } $line); } } } Simone Carletti, Altura Labs
  105. Template Method: example $t = 'This is the title'; $c = array('First entry', 'Second entry'); $o = new FeedPage($t, $c); $o->generate(); $o = new HtmlPage($t, $c); $o->generate(); <?xml version=\"1.0\"?> <rss version=\"2.0\"> <channel> <title>This is the title</title> <item><title>First entry</title></item> <item><title>Second entry</title></item> </rss> </channel> <html> <head><title>This is the title</title></head> <body> First entrySecond entry</body> </html> Simone Carletti, Altura Labs
  106. Template Method: in the wild   Propel bases the full public API on a custom implementation of the Template Method pattern.   BaseClass is the “abstract” class   Class extends BaseClass and overwrites only those methods you want to customize Simone Carletti, Altura Labs
  107. Template Method: using & abusing   Avoid creating abstract classes that forces concrete classes to implement tons of methods Simone Carletti, Altura Labs
  108. Strategy Simone Carletti, Altura Labs
  109. Strategy: problem & solution Problem Solution   You have a complex operation   The Strategy pattern defines a that might vary algorithms at family of algorithms, runtime and you want to encapsulate each one, and encapsulate algorithms make them interchangeable   You want to be able to easily   Strategy lets the algorithm test the algorithms vary independently from clients that use it, often at   You want to be able to add, runtime level remove or change an algorithm without changing the global operation logic Simone Carletti, Altura Labs
  110. Strategy: considerations   Strategy is an excellent example of composition and delegation   Strategy is an alternative to subclassing   Strategy and Template Method patterns expose different approach to a similar problem   Duck Typing is a common practice in Strategy pattern Simone Carletti, Altura Labs
  111. Strategy: example interface Sorter { class ArraySorter public function sort(); { } protected $_a; class SelectionSort implements Sorter public function __construct($a) { { public function sort($array) $this->_a; { return self; // selection sort algorithm } } } public function sortWithAlgorithm($algorithm) { class InsertionSort implements Sorter return $algorithm->sort($this->_a); { } public function sort($array) } { // insertion sort algorithm } } $array = array('white', 'green', 'black', 'red'); $sorter = new ArraySorter($a); class SuperSecretSort implements Sorter { $sorter->sortWithAlgorithm(new SelectionSort()); public function sort($array) $sorter->sortWithAlgorithm(new InsertionSort()); { // insertion sort algorithm } } Simone Carletti, Altura Labs
  112. Strategy: example with Lazy Instantiation class ArraySorter $array = array('white', 'green', 'black', 'red'); { $sorter = new ArraySorter($a); protected $_a; $sorter->sortWithAlgorithm('SelectionSort'); public function __construct($a) $sorter->sortWithAlgorithm('InsertionSort'); { $this->_a; return self; } public function sortWithAlgorithm($algorithm) { require_once $algorithm; $sorter = new $algorithm(); return $sorter->sort($this->_a); } } Simone Carletti, Altura Labs
  113. Strategy: in the wild   Zend_Pdf_Resource_Image_Png allows different image compression strategies (work in progress)   Symfony enables you to configure different escaping strategies with the escaping_strategy variable in your configuration file Simone Carletti, Altura Labs
  114. Strategy: using & abusing   Make sure you are not coupling the context with a specific strategy   Be careful when using one strategy as the default one Simone Carletti, Altura Labs
  115. Time is running out… … but there are many other interesting Design Patterns out of there.   Registry   Mock Object   Command   Decorator   Chain or Responsibility   Data Mapper   Active Record   Table Data Gateway and Row Data Gateway Simone Carletti, Altura Labs
  116. Beyond this Presentation Simone Carletti, Altura Labs
  117. Literature Simone Carletti, Altura Labs
  118. Readings   http://www.fluffycat.com/PHP-Design-Patterns/   http://www.phppatterns.com/   http://www.devarticles.com/c/a/PHP/Introduction-to-Design- Patterns-Using-PHP/   http://www.ibm.com/developerworks/library/os-php-designptrns/   http://www.phplibrairies.com/tutorial_design-pattern_en.html Simone Carletti, Altura Labs
  119. Q&A (part 2/2) Simone Carletti, Altura Labs
  120. Thank you! weppos@weppos.net www.simonecarletti.com Slides will be available at www.slideshare.net/weppos Simone Carletti, Altura Labs

+ Simone CarlettiSimone Carletti, 7 months ago

custom

2975 views, 17 favs, 6 embeds more stats

An introduction to Design Patterns and reusable OOP more

More info about this document

© All Rights Reserved

Go to text version

  • Total Views 2975
    • 2512 on SlideShare
    • 463 from embeds
  • Comments 3
  • Favorites 17
  • Downloads 246
Most viewed embeds
  • 276 views on http://www.simonecarletti.com
  • 93 views on http://www.simonecarletti.it
  • 71 views on http://www.mrkindy.com
  • 21 views on http://disole.wordpress.com
  • 1 views on http://static.slideshare.net

more

All embeds
  • 276 views on http://www.simonecarletti.com
  • 93 views on http://www.simonecarletti.it
  • 71 views on http://www.mrkindy.com
  • 21 views on http://disole.wordpress.com
  • 1 views on http://static.slideshare.net
  • 1 views on http://cc.bingj.com

less

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

Cancel
File a copyright complaint
Having problems? Go to our helpdesk?

Categories

Groups / Events