Code : Tout sélectionner
<?php
// DIC Class WIP by TheKitsuneWithATie
class Container
{
/**
* @var array Filters.
*/
private $_filters = array('set' => array(), 'get' => array());
/**
* @var array Mapped variables.
*/
private $_map = array();
public function __construct()
{
// Adding default classes get filter
$this->addGetFilter('*', function($container, &$value, &$output) {
if (is_array($value) && isset($value['class'])) {
// If an instance is stored, the return it
if (isset($value['instance'])) {
$output = $value['instance'];
return;
}
// Fixing parameters
$args = isset($value['args']) ? $value['args'] : array();
$shared = isset($value['shared']) ? $value['shared'] : true;
$inject = isset($value['inject']) ? $value['inject'] : array();
$reflection = new \ReflectionClass($value['class']);
$instance = $reflection->newInstanceArgs($args);
// Storing the instance if the class is shared
if ($shared)
$value['instance'] = $instance;
if (is_subclass_of($instance, __CLASS__)) {
foreach ($inject as $dependency)
$instance->{$dependency} = $this->{$dependency};
}
$output = $instance;
}
});
}
public function __set($name, $value)
{
// Calling filters
foreach ($this->_filters['set'] as $filter) {
if (preg_match($filter['pattern'], $name)) {
$filter['filter']($this, $value);
}
}
$index = &$this->_goto($name, true);
$index = $value;
}
public function __get($name)
{
$index = &$this->_goto($name);
$return = $index;
// The isset function should be used beforehand to avoid this exception
if ($index === null)
throw new \Exception("Cannot get unset variable '$name'.");
// Calling filters
foreach ($this->_filters['get'] as $filter) {
if (preg_match($filter['pattern'], $name))
$filter['filter']($this, $index, $return);
}
return $return;
}
public function __call($method, $args)
{
$index = &$this->_goto($method);
if ($index === null)
throw new \Exception("Cannot call unset function '$method'.");
if (!is_callable($index))
throw new \Exception("Cannot call non-callable '$method'.");
return call_user_func_array($index, $args);
}
public function __isset($name)
{
return ($this->_goto($name) !== null);
}
public function __unset($name)
{
$index = &$this->_goto($name);
$index = null;
}
/**
* Adds a filter called when setting a variable.
*
* @param string $pattern Regex pattern of the variables to filter
* @param callable $filter Filter
*
* @return $this
*/
public function addSetFilter($pattern, $filter)
{
return $this->_addFilter('set', $pattern, $filter);
}
/**
* Adds a filter called when getting a variable.
*
* @param string $pattern Regex pattern of the variables to filter
* @param callable $filter Filter
*
* @return $this
*/
public function addGetFilter($pattern, $filter)
{
return $this->_addFilter('get', $pattern, $filter);
}
/**
* Adds a filter called when getting or setting a variable.
*
* @param string $type Either 'get' or 'set'
* @param string $pattern Regex pattern of the variables to filter
* @param callable $filter Filter
*
* @return $this
*/
private function _addFilter($type, $pattern, $filter)
{
$pattern = '#' . str_replace('*', '.*', $pattern) . '#';
$this->_filters[$type][] = array(
'pattern' => $pattern,
'filter' => $filter
);
return $this;
}
/**
* Returns a reference of mapped array index according to the path.
*
* @param string $path Path to go to
* @param boolean $fix Will it create missing indexes from the path
*
* @return mixed|null Reference to the index or null if nothing matches the path
*/
private function &_goto($path, $fix = false)
{
$path = explode('_', $path);
$pointer = &$this->_map; // Initializing pointer
$return = $pointer; // Return value
// Going throught the path
foreach ($path as $index) {
if (!isset($pointer[$index])) {
// Create missing indexes if the path needs to be fixed
if ($fix) {
$pointer[$index] = null;
}
// Stop if the path doesn't continue
else {
$return = null;
break;
}
}
// Updating the pointer
$pointer = &$pointer[$index];
}
// Updating return value
if ($return !== null)
$return = &$pointer;
return $return;
}
}Code : Tout sélectionner
<?php
require 'classes/ContainerChild.php';
class ContainerTest extends PHPUnit_Framework_TestCase
{
private $container;
public function setUp()
{
$this->container = new \Bonzai\core\di\Container;
}
/**
* Setting and getting a variable.
*/
public function testVariable()
{
$container = $this->container;
$container->testVar = true;
$retreived = $container->testVar;
$this->assertTrue($retreived);
}
/**
* Checking if a variable is set.
*/
public function testIssetVariable()
{
$container = $this->container;
$container->testIssetVar = true;
$isset = isset($container->testIssetVar);
$this->assertTrue($isset);
}
/**
* Unsetting a variable.
*/
public function testUnsetVariable()
{
$container = $this->container;
$container->testUnsetVar = true;
unset($container->testUnsetVar);
$isset = isset($container->testUnsetVar);
$this->assertFalse($isset);
}
/**
* Mapping a function.
*/
public function testMapFunction()
{
$container = $this->container;
$container->testFunction = function($int) { return $int * $int; };
$square = $container->testFunction(3);
$this->assertEquals(9, $square);
}
/**
* Mapping a class.
*/
public function testMapClass()
{
$container = $this->container;
$container->testMap_class = '\ContainerChild';
$instance = $container->testMap;
$this->assertInstanceOf('ContainerChild', $instance);
}
/**
* Mapping a non shared class.
*/
public function testMapClassNonShared()
{
$container = $this->container;
$container->testMapNonShared_class = '\ContainerChild';
$container->testMapNonShared_shared = false;
$first = $container->testMapNonShared;
$second = $container->testMapNonShared;
$this->assertNotSame($first, $second);
}
/**
* Mapping a class with "chain injection".
*/
public function testMapClassChainInject()
{
$container = $this->container;
$container->testMapInject_class = '\ContainerChild';
$container->testMapInjectSecond_class = '\ContainerChild';
$container->testMapInjectSecond_inject = array('testMapInject');
$first = $container->testMapInject;
$second = $container->testMapInjectSecond->testMapInject;
$this->assertSame($first, $second);
}
/**
* Adding a set filter.
*/
public function testAddSetFilter()
{
$container = $this->container;
$container->addSetFilter('*', function($c, &$v) {
$v = true;
});
$container->testVarSetFilter = false;
$retreived = $container->testVarSetFilter;
$this->assertTrue($retreived);
}
/**
* Adding a get filter.
*/
public function testAddGetFilter()
{
$container = $this->container;
$container->addGetFilter('*', function($c, &$v, &$o) {
$o = false;
});
$container->testVarGetFilter = true;
$retreived = $container->testVarGetFilter;
$this->assertFalse($retreived);
}
}Code : Tout sélectionner
$container->path_to_var = true;Code : Tout sélectionner
$retreived = $container->path_to_var;Code : Tout sélectionner
$container->db_pdo = array('class' => '\PDO',
'args' => array('127.0.0.1', 'root', ''),
'shared' => false);
$pdo = $container->db_pdo;Code : Tout sélectionner
$container->test1 = array('class' => '\ContainerChild');
$container->test2 = array('class' => '\ContainerChild',
'inject' => array('test1'));
$test1 = $container->test2->test1;