2.4. Lazy Resolution

Usually, you will not want arguments or values resolved at the time you specify them. For example, you may want a specify a new object instance as a constructor argument, but of course you don't want to instantiate that object at the moment of configuration. Instead, you probably want to instantiate it only at the moment of construction.

The Definitions class provides methods to allow for late resolution of arguments via Lazy instances. These Lazy arguments are resolved only as the Container reads from the Definitions.

2.4.1. Environment Variables

env(string $varname[, string $vartype = null]) : Lazy\Env

Resolves to the value of the $varname environment variable.

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->env('BAR') // getenv('BAR')
    );

You may optionally specify a type to cast the value to:

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->env('BAR', 'int') // (int) getenv('BAR')
    );

2.4.2. Comma-Separated Environment Variables

csEnv(string $varname[, string $vartype = null]) : Lazy\CsEnv

Resolves to an array of comma-separated values from the $varname environment variable. This is useful when you have to read from a list of values via an environment string; for example:

NOTIFY_EMAILS="foo@example.com,bar@example.net,baz@example.org"
$def->{Notifier::CLASS}
    ->argument(
        'addresses',
        $def->csEnv('NOTIFY_EMAILS') // str_getcsv(getenv('NOTIFY_EMAILS'))
    );

You may optionally specify a type to cast all of the values to:

$def->{IdList::CLASS}
    ->argument(
        'ids',
        $def->csEnv('ID_LIST', 'int')
    );

2.4.3. Any Callable

call(callable $callable) : Lazy\Call

Resolves to the result returned by a callable; the callable must have this signature ...

function (Container $container)

... and may specify the return type.

For example:

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->call(
            function (Container $container) {
                $bar = $container->new(Bar::CLASS);
                // do some work with $bar, then:
                return $bar->getValue();
            }
        )
    );

2.4.4. Function Calls

functionCall(string $function, ...$arguments) : Lazy\FunctionCall

Resolves to the return of a function call.

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->functionCall('barfunc') // barfunc()
    );

Any or all of the $arguments themselves can be Lazy as well.

2.4.5. Static Method Calls

staticCall(string|Lazy $class, string $method, ...$arguments) : Lazy\StaticCall

Resolves to the return of a static method call.

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->staticCall('Bar', 'func') // Bar::func()
    );

Any or all of the $arguments themselves can be Lazy as well.

2.4.6. Shared Instances From The Container

get(string|Lazy $id) : Lazy\Get

Resolves to an identified definition returned by Container::get().

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->get(Bar::CLASS) // $container->get(Bar::CLASS)
    );

2.4.7. Shared Instance Method Calls

getCall(string|Lazy $id, string $method, ...$arguments) : Lazy\GetCall

Resolves to a method call on an object returned by Container::get().

$def->{Foo::CLASS}
    ->method(
        'setBarVal',
        $def->getCall(Bar::CLASS, 'getValue') // $container->get(Bar::CLASS)->getValue()
    );

Any or all of the $arguments themselves can be Lazy as well.

2.4.8. New Instances From The Container

new(string|Lazy $id) : Lazy\NewInstance

Resolves to an identified definition returned by Container::new().

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->new(Bar::CLASS) // $container->new(Bar::CLASS)
    );

// --> $container->new(Bar::CLASS)

2.4.9. New Instance Method Calls

newCall(string|Lazy $id, string $method, ...$arguments) : Lazy\NewCall

Resolves to a method call on an object returned by Container::new().

$def->{Foo::CLASS}
    ->method(
        'setBarVal',
        $def->newCall(Bar::CLASS, 'getValue') // $container->new(Bar::CLASS)->getValue()
    );

Any or all of the $arguments themselves can be Lazy as well.

2.4.10. Callable Factories

callableGet(string|Lazy $id) : Lazy\CallableGet

callableNew(string|Lazy $id) : Lazy\CallableNew

These resolve to a closure around Container::get() or Container::new(). Useful for providing factories to other containers or locators.

$def->{Foo::CLASS}
    ->argument(
        'bar',
        $def->callableGet(Bar::CLASS);
    );

// function () use ($container) { return $container->get(Bar::CLASS); }

2.4.11. Included Files

include(string|Lazy $file) : Lazy\IncludeFile

Resolves to the result returned by including a file; failure to find the file will not terminate execution.

$def->{Foo::CLASS}
    ->method(
        'setBar',
        $def->include('bar.php') // include 'bar.php'
    );

2.4.12. Required Files

require(string|Lazy $file) : Lazy\RequireFile

Resolves to the result returned by requiring a file; failure to find the file will terminate execution.

$def->{Foo::CLASS}
    ->method(
        'setBar',
        $def->require('bar.php') // require 'bar.php'
    );

2.4.13. Array Values

array(array $values) : Lazy\ArrayValues

Resolves to an array, where each element has itself been lazy-resolved.

Each element in the array will be inspected for Lazy resolution. This is a recursive inspection; if an array element is an array, that sub-array will also be lazy-resolved. You can mix Lazy and non-Lazy elements together in the array; the non-Lazy elements will be left as-is.

$def->{Foo::CLASS}
    ->argument('list', $def->array([
        $def->env('BAR'), // getenv('BAR')
        'BAZ',
        $def->env('DIB'), // getenv('DIB')
    ])

The ArrayValues object implements ArrayAccess, Countable, and IteratorAggregate, so in many cases you can work with it as if it is an array:

$def->listing = $def->array([
    'bar' => $def->env('BAR')
]);
$def->listing['baz'] = 'BAZ',
$def->listing['dib'] = $def->env('DIB');

$count = count($def->listing); // 3

unset($def->listing['baz']);

foreach ($def->listing as $key => $value) {
    // ...
}

Finally, to merge any iterable into an existing ArrayValues object, use its merge() method:

$def->listing = $def->array([
    'foo',
    'bar',
    'baz' => 'dib',
]);

$def->listing->merge([
    'zim',
    'gir',
    'irk' => 'doom',
]);

/*
$def->listing will now resolve to ...

[
    'foo',
    'bar',
    'baz' => 'dib',
    'zim',
    'gir',
    'irk' => 'doom',
]
*/

The merge() method behaves just like array_merge().

2.4.14. Standalone Definitions

Each definition itself is Lazy and will resolve to a new instance of the specified class as defined.

$def->{Foo::CLASS}
    ->argument(
        'zim',
        $def->newDefinition(Zim::CLASS) // new Zim()
    );

Note that this is different from resolving via the Container as per new(). With a standalone definition, you can specify the arguments, modifiers, factory, etc. separately from whatever the "default" definition is in the Container.