{"id":24,"date":"2011-03-25T14:00:14","date_gmt":"2011-03-25T21:00:14","guid":{"rendered":"https:\/\/www.alexkorn.com\/blog\/?p=24"},"modified":"2011-04-24T15:38:30","modified_gmt":"2011-04-24T22:38:30","slug":"observer-pattern-with-php-5-3-and-closures","status":"publish","type":"post","link":"https:\/\/www.alexkorn.com\/blog\/2011\/03\/observer-pattern-with-php-5-3-and-closures\/","title":{"rendered":"Ridiculously Simple Observer Pattern with PHP 5.3 and Closures"},"content":{"rendered":"<p>\nThe <a href=\"http:\/\/en.wikipedia.org\/wiki\/Observer_pattern\">observer pattern<\/a> is a handy design pattern often used in UI-focused languages like JavaScript, but not often used in PHP. Prior to PHP 5.3, the observer pattern was cumbersome to use and required a lot of objects &#8211; one for every possible <em>observer<\/em>. However, <a href=\"http:\/\/php.net\/manual\/en\/functions.anonymous.php\">anonymous functions<\/a> (<code>Closures<\/code>) in PHP 5.3 can replace the previously used Observer objects. This makes the observer pattern much more practical by reducing the number of classes that you need to make, often for one-time use.\n<\/p>\n<p>\nLet&#8217;s write up our basic Observable object. You may want to make this class abstract since it&#8217;s probably not useful on its own.\n<\/p>\n<pre lang=\"php\">\r\nclass Observable\r\n{\r\n    \/**\r\n     * @var array Map<string eventName, List<Closure observer>> $_observers\r\n     *\/\r\n    protected $_observers = array();\r\n\r\n    \/**\r\n     * @param string $eventName\r\n     * @param array $data\r\n     *\/\r\n    protected final function _fireEvent($eventName, array $data = null)\r\n    {\r\n        if (isset($this->_observers[$eventName]))\r\n        {\r\n            foreach ($this->_observers[$eventName] as $observer)\r\n            {\r\n                $observer($data);\r\n            }\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * @param string $eventName\r\n     * @param Closure $observer With parameter (array $data)\r\n     *\/\r\n    public final function addObserver($eventName, Closure $observer)\r\n    {\r\n        if (!isset($this->_observers[$eventName]))\r\n        {\r\n            $this->_observers[$eventName] = array();\r\n        }\r\n        $this->_observers[$eventName][] = $observer;\r\n    }\r\n\r\n    \/**\r\n     * @param string $eventName\r\n     * @param Closure $observer The observer to remove\r\n     *\/\r\n    public final function removeObserver($eventName, Closure $observer)\r\n    {\r\n        if (isset($this->_observers[$eventName]))\r\n        {\r\n            foreach ($this->_observers[$eventName] as $key => $existingObserver)\r\n            {\r\n                if ($existingObserver === $observer)\r\n                {\r\n                    unset($this->_observers[$eventName][$key]);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>\nNow that we have the basic observable class, let&#8217;s look at a simple example:\n<\/p>\n<pre lang=\"php\">\r\nclass Person extends Observable\r\n{\r\n    protected $_name;\r\n    protected $_friends = array();\r\n\r\n    public function __construct($name)\r\n    {\r\n        $this->_name = $name;\r\n    }\r\n\r\n    public function getName()\r\n    {\r\n        return $this->_name;\r\n    }\r\n\r\n    public function getIntroducedTo(Person $person)\r\n    {\r\n        $this->_friends[] = $person;\r\n        $this->_fireEvent('introduced', array('other' => $person, 'me' => $this));\r\n    }\r\n\r\n}\r\n\r\n$sally = new Person('Sally');\r\n$sally->addObserver('introduced', function(array $data)\r\n    {\r\n        echo 'Hi, ' . $data['other']->getName() . ', my name is ' .\r\n            $data['me']->getName() . '.';\r\n    });\r\n\r\n$sally->getIntroducedTo(new Person('Harry'));\r\n<\/pre>\n<p>\nThe output will be <code>\"Hi, Harry, my name is Sally.\"<\/code>. Note that you can easy modify the greeting Sally uses from outside that <code>Person<\/code> object without changing the functionality of adding the friend.\n<\/p>\n<p>\nAnd there you have it &#8211; the observer pattern and an example, in less than 75 lines of code!<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>The observer pattern is a handy design pattern often used in UI-focused languages like JavaScript, but not often used in PHP. Prior to PHP 5.3, the observer pattern was cumbersome to use and required a lot of objects &#8211; one for every possible observer. However, anonymous functions (Closures) in PHP 5.3 can replace the previously [&hellip;]<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[18,6],"class_list":["post-24","post","type-post","status-publish","format-standard","hentry","category-tutorials","tag-design-patterns","tag-php"],"_links":{"self":[{"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/comments?post=24"}],"version-history":[{"count":0,"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/posts\/24\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/media?parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/categories?post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.alexkorn.com\/blog\/wp-json\/wp\/v2\/tags?post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}