DI52 decorator pattern support 02

Decorator pattern support added to the di52 library.

New methods

With version 1.2.5 I’ve added decorator pattern support to the di52 package; two new methods are now available to support it.
A closure based solution common to many dependency injection containers has always been available with a syntax like this (from the package README file):

class A implements SomeInterface { public function out(){ return 'foo'; } } class B implements SomeInterface { protected $interface; public function __construct(SomeInterface $interface){ $this->interface = $interface; } public function out(){ return $this->interface->out() . 'bar'; } } class C implements SomeInterface { protected $interface; public function __construct(SomeInterface $interface){ $this->interface = $interface; } public function out(){ return 'baz' . $this->interface->out(); } } $container->bind('SomeInterface', function($container){ $base = $container->make('A'); return new C(new B($base)); }); 

The same could not be said, due to its lack of closure support, for a PHP 5.2 compatible solution.
Again from the README file the last lines can now be written like this:

$decoratorsChain = array('C', 'B', 'A'); $container->bindDecorators('SomeInterface', $decoratorsChain); 

or like this to have the decorator chain treated as a singleton:

$decoratorsChain = array('C', 'B', 'A'); $container->singletonDecorators('SomeInterface', $decoratorsChain); 

A more practical example

Examples based around classes with sudo names like A,B and C are fine if I can understand the pattern in the first place.
A more practical example might be one where I have a base PostRepository class implementing the PostRepositoryInterface in the WordPress echosystem:

class PostRepository implements PostRepositoryInterface { public function getPosts(array $args = array()){ return get_posts($args); } } 

I have a first CachedPostRepository decorator:

class CachedPostRepository implements PostRepositoryInterface{ private $repository; private $cache; public function __construct(PostRepositoryInterface $repository, CacheInterface $cache){ $this->repository = $repository; $this->cache = $cache; } public function getPosts(array $args = array()){ sort($args); $cacheKey = serialize($args); $cached = $this->cache->fetch($cacheKey) if(empty($cached){ $posts = $this->repository->getPosts($args); } $this->cache->store($cacheKey, $posts); return $posts; } } 

and an UserAccessPostRepository decorator:

class UserAccessPostRepository implements PostRepositoryInterface{ private $repository; public function __construct(PostRepositoryInterface $repository){ $this->repository = $repository; } public function getPosts(array $args = array()){ $args = $this->filterAccessiblePostTypes($args); return false != $args ? $this->repository->getPosts($args) : array(); } protected filterAccessiblePostTypes(array $args){ $postTypes = (array)$args['post_type']; $args['post_type'] = array_intersect($postTypes, $this->allowedPostTypesForUser()); return count($args['post_type']) ? $args : false; } protected function allowedPostTypesForUser(){ return (array)get_user_meta(get_current_user_id(), '_allowedPostTypes'); } } 

The power of the decorator pattern is that decorators can be inserted and removed from the chain without the limits a concrete implementation based on inheritance would pose.
In the application bootstrap file I could then do this and conditionally add decorators as required by the application:

$container = new tad_DI52_Container(); $decoratorsChain = array(); if(get_option('_appShouldCache')){ $decoratorsChain[] = 'CachedPostRepository'; } if(get_option('_appShouldRestrictAccess')){ $decoratorsChain[] = 'UserAccessPostRepository'; } $decoratorsChain[] = 'PostRepository'; $container->bindDecorators('PostRepositoryInterface', $decoratorsChain); // later $postRepository = $container->make('PostRepositoryInterface'); 


I’ve got a pair of other itches I’d like to scratch and that I will tackle next: custom bindings and performance.

I appreciate your input