Zend\ServiceManager¶
Introduction¶
The Service Locator design pattern is implemented by the Zend\ServiceManager
component.
The Service Locator is a service/object locator, tasked with retrieving other objects.
Following is the Zend\ServiceManager\ServiceLocatorInterface
API:
1 2 3 4 5 6 7 | namespace Zend\ServiceManager;
interface ServiceLocatorInterface
{
public function get($name);
public function has($name);
}
|
has($name)
, tests whether theServiceManager
has a named service;get($name)
, retrieves a service by the given name.
Additional API¶
A Zend\ServiceManager\ServiceManager
is an implementation of the ServiceLocatorInterface
.
In addition to the above described methods, the ServiceManager
provides additional API:
Service registration¶
ServiceManager::setService
allows you to register an object as a service:
1 2 3 4 5 | $serviceManager->setService('my-foo', new stdClass());
$serviceManager->setService('my-settings', array('password' => 'super-secret'));
var_dump($serviceManager->get('my-foo')); // an instance of stdClass
var_dump($serviceManager->get('my-settings')); // array('password' => 'super-secret')
|
Invokables (constructor-less services)¶
ServiceManager::setInvokableClass
allows you to tell the ServiceManager
what class to instantiate when a
particular service is requested:
1 2 3 | $serviceManager->setInvokableClass('foo-service-name', 'Fully\Qualified\Classname');
var_dump($serviceManager->get('foo-service-name')); // an instance of Fully\Qualified\Classname
|
Classes registered as invokables must have no constructor defined, or constructors that allow passing no arguments.
Service factories¶
Instead of an actual object instance or a class name, you can tell the ServiceManager
to invoke
a provided factory in order to get the object instance. Factories may be either a PHP callback,
an object implementing Zend\ServiceManager\FactoryInterface
, or the name of a class
implementing that interface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class MyFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
return new \stdClass();
}
}
// registering a factory instance
$serviceManager->setFactory('foo-service-name', new MyFactory());
// registering a factory by factory class name
$serviceManager->setFactory('bar-service-name', 'MyFactory');
// registering a callback as a factory
$serviceManager->setFactory('baz-service-name', function () { return new \stdClass(); });
var_dump($serviceManager->get('foo-service-name')); // stdClass(1)
var_dump($serviceManager->get('bar-service-name')); // stdClass(2)
var_dump($serviceManager->get('baz-service-name')); // stdClass(3)
|
Service aliasing¶
With ServiceManager::setAlias
you can create aliases of any registered
service, factory or invokable, or even other aliases:
1 2 3 4 5 6 7 8 9 10 | $foo = new \stdClass();
$foo->bar = 'baz!';
$serviceManager->setService('my-foo', $foo);
$serviceManager->setAlias('my-bar', 'my-foo');
$serviceManager->setAlias('my-baz', 'my-bar');
var_dump($serviceManager->get('my-foo')->bar); // baz!
var_dump($serviceManager->get('my-bar')->bar); // baz!
var_dump($serviceManager->get('my-baz')->bar); // baz!
|
Abstract factories¶
An abstract factory can be considered as a “fallback” factory. If the service manager was not able to find a service for the requested name, it will check the registered abstract factories:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\AbstractFactoryInterface;
class MyAbstractFactory implements AbstractFactoryInterface
{
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
// this abstract factory only knows about 'foo' and 'bar'
return $requestedName === 'foo' || $requestedName === 'bar';
}
public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
$service = new \stdClass();
$service->name = $requestedName;
return $service;
}
}
$serviceManager->addAbstractFactory('MyAbstractFactory');
var_dump($serviceManager->get('foo')->name); // foo
var_dump($serviceManager->get('bar')->name); // bar
var_dump($serviceManager->get('baz')->name); // exception! Zend\ServiceManager\Exception\ServiceNotFoundException
|
Initializers¶
You may want certain injection points to be always called. As an example, any object you load via
the service manager that implements Zend\EventManager\EventManagerAwareInterface
should likely
receive an EventManager
instance. Initializers can be either PHP callbacks or classes
implementing Zend\ServiceManager\InitializerInterface
. They receive the new instance, and can
then manipulate it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\InitializerInterface;
class MyInitializer implements InitializerInterface
{
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if ($instance instanceof \stdClass) {
$instance->initialized = 'initialized!';
}
}
}
$serviceManager->addInitializer('MyInitializer');
$serviceManager->setInvokableClass('my-service', 'stdClass');
var_dump($serviceManager->get('my-service')->initialized); // initialized!
|
In addition to the above, the ServiceManager
also provides optional ties to Zend\Di
, allowing Di
to act
as an initializer or an abstract factory for the service manager.