Delegates

Delegates are responsible for telling Hiraeth how to configure and create dependencies for the dependency injector. Think of them as an isolated factory class which can use Hiraeth\Application to query configuration information, retrieve related dependencies and return a working object. The core of Hiraeth integration is performed by creating delegates and registering those delegates through the configuration.

Delegates are always bound to a concrete class for which that delegate is responsible for constructing.

Delegates implement Hiraeth\Delegate which has two methods:

Method Description
getClass() Returns the class name for which the delegate is responsible for constructing
__invoke() Handles the construction of the class and returns the instance

Creating a Delegate

A contrived example in which we need to build our Bar class with a particular setting from our configuration might look as follows:

namespace Acme\Foo;

use Hiraeth;

class BarDelegate implements Hiraeth\Delegate
{
    static public function getClass(): string
    {
        return Bar::class
    }

    public function __invoke(Hiraeth\Application $app): object
    {
        return new Bar($app->getConfig('packages/bar', 'setting', NULL));
    }
}

The __invoke() method receives the application instance which can be used to get configuration or environment information as well as to construct subsequent dependencies via $app->get(). See the PSR-11 documentation for a complete description of DI related methods.

Registering a Delegate

Once our class is added and our autoloader is aware of it, we can register the delegate in any config file under the [application] section. Hiraeth scans all [application] sections on startup and registers the delegates as factories for the class they identify.

[application]

    delegates = [
        "Acme\Foo\BarDelegate"
    ]

Now, anywhere that dependency injection is used, if we were to typhint our Bar class, Hiraeth will use the delegate to construct and return the object as built by the delegate.

class MyAction
{
    public function __construct(Bar $bar)
    {
        $this->bar = $bar;
    }
}

Singletons

If you always need the same instance of a given class, you can share the constructed instance of that class inside the delegate. Once shared, the dependency injector will no longer construct a new instance when its injected, but will always return the previously constructed instance. We can modify the original delegate accordingly to see how this behavior is achieved:

public function __invoke(Hiraeth\Application $app): object
{
    $instance = new Bar($app->getConfig('packages/bar', 'setting', NULL));

    return $app->share($instance);
}

Although you can also use delegates to provide dependencies and additional configuration of classes beyond their construction, if this is the only type of class configuration required you can use a provider instead.

Learn About Providers