An advanced dependency injection container

3.0.9 2016-05-26 17:41 UTC


Chernozem is an advanced dependency injection container based on the ArrayAccess PHP core object, like Pimple, but with different features.

Dependency injection is a design pattern to make better encapsulation of external objects into another object. Fabien Potencier has written an article about that, I advise you to read it:

With dependency injection containers, you can inject values with an array writing and so configure your object. It is very helpful because extending those containers will drop much of your setters/getters and provide a robust implementation. Many tools use those containers like the Lumy or Silex framework.


Pick up the source or install it with Composer :

composer require pyrsmk/chernozem


You can pass an array or a Traversable object to the constructor to add values directly to your container or set some of your internal properties (we'll see all this later) :

$container=new SampleClass(array(
    'foo'       => false,
    'bar'       => 0.758,
    'foobar'    => function(){
        return 'something';
// Print 0.758
echo $container['bar'];

If you want, you can instantiate Chernozem itself and use it directly :

$container=new Chernozem(array('some','values'));
foreach($container as $key=>$value){
    echo "$key : $value\n";
    This will echo :

    0 : some
    1 : values
    foo : bar

The container

As we said, Chernozem works as a value container. Let's see how :

// Instantiate a Chernozem child
$container=new SampleClass;
// Add a value
// Get a value
echo $container['foo'];
// Verify existence
    echo 'foo exists';
// Drop
    echo 'foo does not exists';

As you can see, it supports all basic array operations, numeric keys and even the [] syntax :


Moreover, you can use objects as keys:

$object=new stdClass();
// Print 72
echo $container[$object];

Chernozem implements two interfaces : Countable and Iterator. That means you can use the count() PHP function to know how many values are into the container and the foreach() structure control to iterate over your Chernozem object.

// Print the number of elements in the container
echo count($container);
// Iterate
foreach($container as $key=>$value){
    echo $value;

And if you want to retrieve all values from the container,you can use the toArray() method:

// Will print all registered values

Internal object properties

By extending Chernozem, you can modify properties from your objects with the following rules :

  • $var properties are editable
  • $_var aren't but are still accessible
  • $__var properties are not editable neither accessible
  • only strings are allowed as keys
  • you cannot use unset
  • properties are not count by the count() function
  • foreach() does not iterate other properties but only over container values
  • toArray() does not return any property
  • properties have priority over container values

But here's the most interesting part!

class SampleClass{

    protected $foo='blahblah';
    protected $_bar=72;
    protected $__foobar;

// Print 'blahblah'
echo $container['foo'];
// Print 'lollipop'
echo $container['foo'];
// Print '72'
echo $container['bar'];
// This will throw an exception
// This line will print nothing,
// since $__foobar is not accessible at all
// the returned value will be from the container instead from a propery
echo $container['foobar'];


Closure values can be set as services. That means the closure will be automatically executed when the user will retrieve it. It's really useful to initialize objects on-demand to save resources. When initialized, the object will be saved as the real value of the specified key. Here's a quick example with Twig :

// Set initialization closure for Twig
    require_once '/path/to/lib/Twig/Autoloader.php';
    $twig=new Twig_Environment(
        new Twig_Loader_Filesystem('/path/to/templates'),
    return $twig;
// Define that closure as a service

Now, when you'll access to the twig value you won't have the closure itself, but the initialized Twig object :

// Render a template

If you want to remove the twig closure as a service, just do :


Chaining arrays

You can't chain arrays to modify or retrieve a value with Chernozem, this is due to a PHP limitation with ArrayAccess. The basic way to handle this case is :

// Retrieve 'foo' array
// Add 'bar' to the array
// Update 'foo' value

But to simplify this, you can declare a Chernozem object instead of an array as your container value, then you'll be able to chain :

$container['foo']=new Chernozem(array('bar'=>72));
// Print '72'
echo $container['foo']['bar'];
// Print '42'
echo $container['foo']['bar'];

Last remarks

For performance purpose, if you want to access to container values from a Chernozem child, please use $this->__chernozem_values['foo'] rather than $this['foo'].


Chernozem is published under the MIT license.