di52 getting ready for the next fight

Adding the finishing touches on the second version of the PHP 5.2 compatible Dependency Injection container.

Old tricks

The new version, while tagged 2.0, will not break compatibility with version 1.0.
The focus of this new version was to speed up the container to insane levels with some heavy refactoring while keeping the existing functions and API.
That’s a commitment I’ve been able to keep so far and I’ve not intention of dropping; I will update the documentation with more examples and use cases and with almost 1.5 years of use on the field I’ve been able to asses di52 utility way beyond its PHP 5.2 compatibility.
The Laravel Service Container like API, with some sprikles of Pimple together with its lack of external dependencies have made it a tool I rely on in almost any project I work on.

Some new tricks

Most of my work happens on WordPress codebase and WordPress minimum requirements dictate for PHP 5.2 back-compatibility for plugins willing to hit the largest possible user base.
The lack of closures especially poses quite a challenge for a DI container and with that purpose in mind I’ve added some features I needed to DI52.
The first is the possibility to bind an implementation with multiple aliases like this:

globals $acme;

$acme = $container = new tad_DI52_Container();

$container->singleton(array('messages', 'acme_Interfaces_MessagesI'), 'acme_Messages');

This comes useful when a third party needs to get hold of an implementation provided by the plugin without needing or requiring knowledge about what class of the “Acme” plugin extends which interface:

// in the plugin bootstrap file...

global $acme;

$notFound = $acme->make('messages')->message('not-found');

And when the “Acme” plugin internally spins up its gears resolving a class requiring an implementation of the acme_Interfaces_MessagesI interface:

// file src/Dispatcher.php

class acme_Dispatcher {

    /**
     * @var acme_Interfaces_MessagesI
     */
    private $messages;

    public function __construct( acme_Interfaces_MessagesI $messages ){
        $this->messages = $messages;
    }

    // more methods
}

// in the plugin bootstrap file...
$container->singleton('dispatcher', 'acme_Dispatcher');

Whatever is called first the acme_Interfaces_MessagesI interface will be resolved to the acme_Messages class and stored as a singleton.

Another coming feature will be the easier re-binding of implementations for, again, easier interaction with a plugin code from third parties and easier testing and refactoring of legacy code heavily relying on [Singleton pattern] implementations:

class Dependency {

    private $instance;

    public static function instance(){
        if(empty(self::$instance))
            self::$instance = new self();

        return self::$instance;
   }

   private function __construct() {}
}

class Legacy {

    public function __construct(){
        // how to mock this in a test?
        $dependency = Dependency::instance();
    }

    // more methods
}

Refactoring the Dependency class a little:

class Dependency {

    public static function instance(){
        global $acme;

        if(empty($acme['dependency']))
            $acme['acme.dependency'] = new self();

        return $acme['acme.dependency'];
   }

   private function __construct() {}
}

I can now write this in a test:

$dependency = $this->getMock('Dependency');
$dependency->expects(...)

global $acme;

$acme->bind('acme.dependency', $dependency);

// now I can mock Dependency!
$legacy = new Legacy();

Next

I will release in the next days and post an update with a panoramic view of the new features.