Upload
bo-andersen
View
165
Download
1
Embed Size (px)
Citation preview
ZF2 Service Managerby Bo Andersen
What is the service manager all about?Implements the service locator design pattern
A central registry from which services (less formally, objects) are retrieved
Services are retrieved by a key
Keys must be unique across all modules; services are stored within an array in Zend\ServiceManager\ServiceManager
Lazily instantiates services when they are needed
When retrieving an object, one does not need to worry about instantiating it
Therefore, an object’s dependencies have already been resolved when the object is retrieved
More than a key-value registry as Zend_Registry in ZF1
A small disclaimer...Usually configured in a configuration file within each module
The module manager automatically merges these configuration files
The configuration files contain a PHP array
In this presentation, an imperative approach is used instead
That is, instead of large arrays, an object-oriented approach is used instead
This keeps everything more intuitive and easy to understand while discussing the theory
This is not the most common approach - don’t worry, we will work with the normal approach throughout the rest of the course!
Furthermore, to keep things simple, we will not include namespaces in the service keys in this presentation
Walkthrough of the service types
InvokablesA string that contains a fully qualified class name (i.e. including the
namespace)
When requesting an invokable, the service manager instantiates the class and returns the object
Adding an invokable to the service manager
$serviceManager->setInvokableClass('userService', 'User\Service\UserService');
Example: Retrieving an invokableWhen retrieving services, one does not need to know its type
An invokable is retrieved just like any other type of service
Retrieving a service
$userService = $serviceManager->get('userService');
Internally within the service manager
// $className contains 'User\Service\UserService'
return new $className();
FactoriesUsed to perform any setup or dependency injection for the requested
object
Either a PHP callable, an object or a fully qualified class name
If an object or class name, Zend\ServiceManager\FactoryInterface must be implemented (defines a createService method, which is invoked by the service manager)
In all cases, the object that is to be fetched should be returned
Factories are mostly used if the fetched object has dependencies that need to be resolved
Example: Adding & retrieving a factory$serviceManager->setFactory('userService', function($serviceManager) {
$logger = $serviceManager->get('My\Logger');
return new \User\Service\UserService($logger);
});
Fetching the service remains the same
$userService = $serviceManager->get('userService');
Abstract FactoriesEssentially a fallback in case a non-existing service is requested from
the service manager
The attached abstract factories will be queried to see if one of them can return the requested service
Two possible approaches; a string representing a fully qualified class name or an object
Zend\ServiceManager\AbstractFactoryInterface must be implemented
This interface defines two methods: canCreateServiceWithName and createServiceWithName
Abstract Factories (continued)public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName);
Determines whether or not the abstract factory can create a service with the provided name (returns boolean)
public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName);
Responsible for creating a service with a given name and returning it. Invoked if canCreateServiceWithName returns TRUE
InitializersA block of code to be executed when a service is retrieved from the
service manager
Can be either a PHP callable, object or string containing a fully qualified class name
If an object or string is used, then the class must implement Zend\ServiceManager\InitializerInterface
The newly created instance is passed and it can thus be manipulated
Can sometimes replace factories
E.g. instead of injecting a database adapter into all repositories, a single initializer can accomplish this
Every service retrieved from the service manager will trigger all of the initializers
Only add an initializer for services that are frequently retrieved, because performance is affected
Example: Adding an initializerInject a database adapter into all services that implement AdapterAwareInterface
$serviceManager->addInitializer(function($instance, $serviceManager) {
if ($instance instanceof Zend\Db\Adapter\AdapterAwareInterface) {
$instance->setDbAdapter($serviceManager->get('Zend\Db\Adapter\Adapter'));
}
});
AliasesAn alias points from one service to another
When a service with an aliased name is requested, a different name should be used instead
For instance, if a service A is an alias for a service B, then a request for service A would actually return service B
Aliases can be of invokables, factories or other aliases (and hence they can be recursive)
This means that a service A can be an alias for service B, which in turn can be an alias for service C, and so on. In this scenario, requesting service A from the service manager would return service C
Aliases (continued)Aliases provide a lot of flexibility, particularly because of ZF2’s
modular structure
An application may be using Zend\Db\Adapter\Adapter for database connectivity
A module can refer directly to this key in the service manager
If for some reason this is no longer the case, then a lot of references would have to be updated
If an alias was used instead, one could do like in the below example
$serviceManager->setAlias('user_db_adapter', 'Zend\Db\Adapter\Adapter');
$dbAdapter = $serviceManager->get('user_db_adapter');
Shared ServicesServices registered with a service manager can be either shared or
not shared
In this context, the term shared refers to whether or not a new instance of a service is created on every request
If a service is shared, then an arbitrary number of requests for a given service will return the exact same object instance. Otherwise, a new instance will be created on every request
Services are shared by default
Example 1: Shared serviceDemonstrating the service manager’s default behavior$userService1 = $serviceManager->get('User\Service\UserService');
$userService2 = $serviceManager->get('User\Service\UserService');
The following line outputs: bool(true)
var_dump((spl_object_hash($userService1) === spl_object_hash($userService2)));
Example 2: Declaring service as not sharedOverriding the service manager’s default behavior
$serviceManager->setShared('User\Service\UserService', false);
$userService3 = $serviceManager->get('User\Service\UserService');
The following line outputs: bool(false)
var_dump((spl_object_hash($userService2) === spl_object_hash($userService3)));
that’s allThis presentation is part of my Zend Framework 2 online course.
Get 50% discount by navigating to the below URL!
https://www.udemy.com/zend-framework-2-from-beginner-to-professional/?couponCode=SS50