Parameters
Container can create a parameters structure to resolve object and dependencies.
Resolve Factories
This is a sample parameters, we set a class name as param: car
, then we can use resolve()
to create it.
use Windwalker\DI\Parameters; $container->setParameters( [ 'car' => MyCar::class ] ); class MyCar {} $car = $container->resolve($container->getParam('car')); // Same as $car = $container->resolve(MyCar::class);
Most of all, object may have some constructor arguments, we can use \Windwalker\DI\create()
to define the factory with some custom arguments.
use Windwalker\DI\Parameters; use function Windwalker\DI\create; $container->setParameters( [ // Define factory by create() 'car' => create( MyCar::class, crew: 4 ) ] ); class MyCar { public function __construct(public int $crew) {} } $car = $container->resolve($container->getParam('car')); // Same as $car = $container->resolve(\Windwalker\ref('car')); // Same as $car = $container->resolveParam('car');
Define Factory with Dependencies
You may need a class with dependencies, for example:
class CachePool { public function __construct(protected StorageInterface $storage) {} }
There are 2 ways to handle dependencies, one is use callback:
[ 'cache' => create( fn (Container $container) => new CachePool( // Also handle FileStorage's dependencies $container->newInstance( FileStorage::class, path: '/path/to/storage/cache', ttl: 300 ) ) ) ]
The second is use configuration with ref()
, ref()
is a wrapper to make Container::getParams()
direct to another position:
[ 'cache' => create( CachePool::class, storage: \Windwalker\ref('storages.file') ), 'storages' => [ 'file' => FileStorage::class ] ]
Or a callback of argument, the first level closure will resolve as argument factory:
[ 'cache' => create( CachePool::class, storage: fn (Container $container) => ->newInstance( FileStorage::class, path: '/path/to/storage/cache', ttl: 300 ) ) ]
If you want to set a pure closure into it, use \Windwalker\raw()
to wrap it.
create( Runner::class, // Use raw() to wrap closure task: \Windwalker\raw( function () { // ... } ) )
Array of Objects
Container can only handle first level of callback, for an array of objects, you must use callback factory to handle dependencies:
Below is not work:
[ 'log' => create( Logger::class, // This will not work, Container won't resolve this factories handlers: [ \Windwalker\ref('log_handlers.file'), \Windwalker\ref('log_handlers.mail'), \Windwalker\ref('log_handlers.redis'), ] ), 'log_handlers' => [ 'file' => FileLogHandler::class, 'mail' => MailLogHandler::class, 'redis' => RedisLogHandler::class, ] ]
Use this instead.
[ 'log' => create( Logger::class, handlers: function (Container $container) { return [ $container->resolveParam('log_handlers.file'), $container->resolveParam('log_handlers.mail'), $container->resolveParam('log_handlers.redis'), ]; } ), // ... ]
About resolve()
resolve()
is a method to handle any object or parameter definitions of Container.
// Send a class name or id, if this name exists in container, will get it. $container->resolve('foo'); $container->resolve(Foo::class); // Send a class name which is not set, will create it. $container->resolve(SomeClass::class); // Send a definition object, will resolve this definition. $container->resolve( new \Windwalker\DI\Definition\StoreDefinition( SomeClass::class ) ); // Send a callback, will call it as factory. $container->resolve(function (\Windwalker\DI\Container $container) { return $container->newInstance(SomeObject::class, ['foo' => $container->get('foo')]); }); // Send a params ref, will get this param value and resolve it $container->resolve(\Windwalker\ref('foo.bar.classname')); // Same as $container->resolveParam('foo.bar.classname');
Merge
You may merge a config array to an exists position.
$container->mergeParameters( 'foo.bar', [ 'yoo' => 'The data you want to merge' ] );
By default, mergeParameters()
won't override exists values, only merge values not exists in Container. If you want to override them, add flag:
$container->mergeParameters( 'foo.bar', [ 'yoo' => 'The data you want to merge' ], $container::MERGE_OVERRIDE );
Also supports recursive:
$container->mergeParameters( 'foo.bar', [ 'yoo' => [ 'goo' => 'The data you want to merge' ] ], $container::MERGE_RECURSIVE );