* The current globally available container (if any).
*
* @var static
*/
protected static $instance = null;
/**
* The container's bindings.
*
* @var array
*/
protected $bindings = null;
/**
* The registered type aliases.
*
* @var array
*/
protected $aliases = null;
function __construct(array $c = [])
{
$this->_container = $c;
}
if (static::$instance)
throw new \Exception('Cannot create another Container instance!');
static::$instance = $this;
function __set($key, $value)
{
/**
* do we really need to stop the variables from being set???
* currently we are protecting anything that is not a callable function.
* the reason why I don't protect a callable, is because many of the callables
* will set the same value to an instantaited object. It just saves us using `unset()` first
* The alternative is to do something like Symfony or other frameworks,
* where we call a `protect()` or `singleton()` methods etc.
* I just hate calling yet another method for every occasion or fringe case!
*/
if (isset($this->_container[$key]) && ! is_callable($this->_container[$key]))
$this->bindings = $c;
if (isset($c['aliases']))
{
$trace = debug_backtrace();
trigger_error(__CLASS__ . " container property `{$key}` has already been set and cannot be changed in {$trace[0]['file']} on line {$trace[0]['line']}. Please unset() and re-set the value!", E_USER_ERROR);
$this->aliases = $c['aliases'];
unset($c['aliases']);
}
else
return $this->_container[$key] = $value;
$this->aliases[__CLASS__] = $this;
}
function __get($key)
/**
* Set the globally available instance of the container.
* Examples of official PHP error messages when a property cannot be found
* Notice: Undefined index: config in C:\...\app.php on line 34
* Undefined property: Container::$config in <b>C:\...\app.php</b> on line <b>111</b><br/>
*/
$trace = debug_backtrace();
trigger_error('Undefined container property: ' . __CLASS__ . "->{$key} in <b>{$trace[0]['file']}</b> on line <b>{$trace[0]['line']}</b>; thrown", E_USER_ERROR);
return null;
}
function __isset($key)
{
return isset($this->_container[$key]);
}
function __unset($key)
{
unset($this->_container[$key]);
return static::$instance;
}
function &__call($method, $args)
{
if (isset($this->_container[$method]))
if (is_callable($this->_container[$method]))
if (isset($this->bindings[$method]))
if (is_callable($this->bindings[$method]))
{
array_unshift($args, $this); // Prepend $this container to the beginning of the function call arguments!
if (preg_match('/^([gs]et|has|isset|unset)([A-Z])(.*)$/', $method, $match))
{
$property = strtolower($match[2]). $match[3];
if (isset($this->_container[$property]))
if (isset($this->bindings[$property]))
{
switch($match[1])
{
case 'get': return $this->_container[$property];
case 'set': return $this->_container[$property] = $args[0];
case 'get': return $this->bindings[$property];
case 'set': return $this->bindings[$property] = $args[0];
case 'has': // fallthrough vvv alias for `isset`
case 'isset': $result = isset($this->_container[$property]); return $result;
case 'unset': $result = null; unset($this->_container[$property]); return $result;
case 'isset': $result = isset($this->bindings[$property]); return $result;
case 'unset': $result = null; unset($this->bindings[$property]); return $result;
}
}
throw new \InvalidArgumentException("Property {$property} doesn't exist");
@ -113,20 +106,129 @@ class Container
@@ -113,20 +106,129 @@ class Container
}
function &get($key, $default = null) // similar to __get()
{
return $this->_container[$key] ?? $default;
return $this->bindings[$key] ?? $default;
}
function has($key) // alias for __isset()
{
return isset($this->_container[$key]);
return isset($this->bindings[$key]);
}
function &merge($key, array $arr) // we need this function because we cannot (re)`set` the arrays to new values without unsetting the old values first! ie. __set() will fail because it already exists!
{
// TODO: Add is_array() checks to the container, and add variable number of array inputs!
* Examples of official PHP error messages when a property cannot be found
* Notice: Undefined index: config in C:\...\app.php on line 34
* Undefined property: Container::$config in <b>C:\...\app.php</b> on line <b>111</b><br/>
*/
$trace = debug_backtrace();
trigger_error('Undefined container property: ' . __CLASS__ . "->{$key} in <b>{$trace[0]['file']}</b> on line <b>{$trace[0]['line']}</b>; thrown", E_USER_ERROR);
return null;
}
/**
* Dynamically set container services.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function __set($key, $value)
{
/**
* do we really need to stop the variables from being set???
* currently we are protecting anything that is not a callable function.
* the reason why I don't protect a callable, is because many of the callables
* will set the same value to an instantaited object. It just saves us using `unset()` first
* The alternative is to do something like Symfony or other frameworks,
* where we call a `protect()` or `singleton()` methods etc.
* I just hate calling yet another method for every occasion or fringe case!
*/
if (isset($this->bindings[$key]) && ! is_callable($this->bindings[$key]))
{
$trace = debug_backtrace();
trigger_error(__CLASS__ . " container property `{$key}` has already been set and cannot be changed in {$trace[0]['file']} on line {$trace[0]['line']}. Please unset() and re-set the value!", E_USER_ERROR);