PHP-DI is an amazing tool, which I think can be summed up nicely by this tweet:

The short version of what it does is this: It uses PHP reflection to examine your code and dynamically determine and inject dependencies.

That is a bit of a mouthful, so let me describe a practical example of a problem PHP-DI could be used to solve.


Lets say you have a PHP library that listens to a chat server. Each server has many chat rooms, each server also has many authors. Authors send messages in channels. You want to allow users of your library to add their own callbacks that get called when a new message is received.

The function could look like this:

function myCallback($server, $channel, $message, $author) {}

This makes sense, but what if the order changes?

function myCallback($message, $author, $channel, $server) {}

What order makes sense? Do we go from the "most inclusive" to "least inclusive?" Or the other way? What if the user of your library does not need to know the server or channel, just the author and message? It would make the script a bit slower to need to look up data the users script would never need, and adds additional overhead that the client definitely does not want.

This is where PHP-DI comes in. It will examine the code being called and dynamically determine what dependencies are required, and only build them if they are needed.

For an actual code example, lets say your library has a method that parses incoming messages that looks like this.

class YourClasss
{
    /**
     * @var $messageData The raw data for the incoming message.
     * @var callable $callback The user defined callback
     */
    public function onMessageReceived($messageData, callable $callback)
    {
        // Retrieve all the data relevant to your 
        $server = getServerFromMessageData($messageData);
        $channel = getChannelFromMessageData($messageData);
        $message = getMessageFromMessageData($messageData);
        $author = getAuthorFromMessageData($messageData);

        // Call the users callback, passing the retrieved data
        $callback($server, $channel, $message, $author);
    }
}

This is pretty straightforward, but what about the problems described above? What if the user-provided callback does not need some of the data? Or maybe they wanted to put their function inputs in a different order? Lets look at how we might implement the same with PHP-DI.

First things first you need to install the library into your application. I won't parrot the getting started guide, but if you use composer it is as simple as "composer require php-di/php-di"

Next we can get back to writing our message parser:

class YourClass
{
    /**
     * @var $messageData The raw data for the incoming message.
     * @var callable $callback The user defined callback
     */
    public function onMessageReceived($messageData, callable $callback)
    {
        // Create a new DI container builder
        $builder = new DI\ContainerBuilder();

        // Tell PHP-DI how to build the various possible dependencies
        // that the callback might have
        $builder->addDefinitions([

            Server::class => DI\factory(function() use ($messageData) {
                return getServerFromMessageData($messageData);
            }),

            Channel::class => DI\factory(function() use ($messageData) {
                return getChannelFromMessageData($messageData);
            }),

            Message::class => DI\factory(function() use ($messageData) {
                return getMessageFromMessageData($messageData);
            }),

            Author::class => DI\factory(function() use ($messageData) {
                return getAuthorFromMessageData($messageData);
            })

        ]);

        // Build the DI container
        $container = $builder->build();

        // Let the container call the callback.
        // It will manage all its dependencies for us
        $container->call($callback);
    }
}

Following the same line of thought, maybe your program has user callbacks for different events. Instead of just "Message Received," maybe you could also in clude stuff like "User has joined chatroom" or "Channel topic has changed." You could use the PHP-DI container to dynamically build the standard context around such events, instead of needing to repeat yourself for every different event you might want to support.

This makes the code a bit more complicated, but it provides the end user with the best experience and avoids wasting time on building depencencies your end user does not need.


So what other practical applications are there for this?

Well that is a difficult question to answer due to how "meta" dependency injection is. It is not really geared to solve a specific problem, but rather to help make solving problems easier.