I came up to the following two simple implementations of DI and SL in my application:
Variant 1
/**
* Get instance of service by name, or register new service.
*
* @param string $name service name
* @param callable $producer callable that returns an instance of service
* @return mixed if producer is not set:
* the instance of service, or NULL, if no such service was registered;
* if producer is set: TRUE
* @throws \LogicException if there is recursion in dependencies
*/
function service( $name, callable $producer = null ) {
static $services = [];
if( $producer ) {
$services[ $name ] = function () use ( $producer ) {
static $service = null;
if( !$service ) {
static $called = false;
if( $called ) {
throw new \LogicException(
'Recursion in dependencies detected');
}
$called = true;
$service = call_user_func( $producer );
$called = false;
}
return $service;
};
return true;
}
return @call_user_func( $services[ $name ] );
}
Variant 2
/**
* Get instance of service by name, or register new service.
*
* @param string $name service name
* @param callable $producer callable that returns an instance of service
* @return mixed if producer is not set:
* the instance of service, or NULL, if no such service was registered;
* if producer is set: TRUE
* @throws \LogicException if there is recursion in dependencies
*/
function service( $name, callable $producer = null ) {
static $producers = [];
static $services = [];
if( $producer ) {
$producers[ $name ] = $producer;
$services[ $name ] = null;
return true;
}
if( !@$services[ $name ] ) {
static $called = [];
if( @$called[ $name ] ) {
throw new \LogicException('Recursion in dependencies detected');
}
$called[ $name ] = true;
$services[ $name ] = @call_user_func( $producers[ $name ] );
$called[ $name ] = false;
}
return $services[ $name ];
}
Example of use
/* services */
class ServiceFoo {}
class ServiceBar {}
class ServiceBaz {
private $foo;
private $bar;
public function __construct( ServiceFoo $foo, ServiceBar $bar ) {
$this->foo = $foo;
$this->bar = $bar;
}
}
/* register services */
service('foo', function () {
return new ServiceFoo();
});
service('bar', function () {
return new ServiceBar();
});
service('baz', function () {
return new ServiceBaz(
service('foo'),
service('bar')
);
});
/* get instance of ServiceBaz */
$baz = service('baz');
Which one of the variants do you suggest to use and why? Are there any pitfalls in these implementations that I had missed?
Aucun commentaire:
Enregistrer un commentaire