Skip to content

Instantly share code, notes, and snippets.

@mdcass
Last active April 9, 2017 22:37
Show Gist options
  • Save mdcass/61ba26bf2fb91091f284c4dd4f5f6512 to your computer and use it in GitHub Desktop.
Save mdcass/61ba26bf2fb91091f284c4dd4f5f6512 to your computer and use it in GitHub Desktop.
Chainable class container

Simple Chain of Responsibility in PHP

Container and Interface for implementing Chain of Responsibility. Allows for variable dependencies per class without hooking into a wider Service Container.

Example

Classes to Chain

<?php

class ResolveNumberOne implements ChainableClass
{
	/**
	 * @var int
	 */
	protected $number;
	
	public function __construct($number)
	{
		$this->number = $number;
	}
	
	public function handle()
	{
		return $this->number === 1 ? 'One' : null;
	}
}

class ResolveNumberTwo implements ChainableClass
{
	/**
	 * @var int
	 */
	protected $number;
	
	public function __construct($number)
	{
		$this->number = $number;
	}
	
	public function handle()
	{
		return $this->number === 2 ? 'Two' : null;
	}
}

Implementation

<?php

$number = 2;

// Returns "Two";
$resolved = (new ChainableClassContainer)
                ->chain(ResolveNumberOne::class, [ $number ])
                ->chain(ResolveNumberTwo::class, [ $number ])
                ->handle();
                
$number = 4;

// Returns null;
$resolved = (new ChainableClassContainer)
                ->chain(ResolveNumberOne::class, [ $number ])
                ->chain(ResolveNumberTwo::class, [ $number ])
                ->handle();
<?php
/**
* Interface for classes which can be used in a ChainableClassContainer
*/
interface ChainableClass
{
public function handle();
}
<?php
/**
* Simple class providing the functionality to chain classes
*/
class ChainableClassContainer
{
/**
* List of classes and their arguments with which to instantiate them
*
* @var array
*/
protected $chain = [];
/**
* @param mixed $class
* @param array $arguments
* @return $this
*/
public function chain($class, array $arguments = [])
{
$this->chain[] = [
$class,
$arguments
];
return $this;
}
/**
* Traverse the list of chainable classes, instantiating, and moving on
* if their handle method returns null
*
* @return mixed|null
* @throws \Exception When Class in chain doesn't implement ChainableClass interface
*/
public function handle()
{
$processed = null;
foreach($this->chain as $handler)
{
$processed = (new $handler[0](...$handler[1]))->handle();
if($processed !== null)
break;
}
return $processed;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment