I'm trying to understand some principles of the ZendFramework 2, and I want to know why to inject services on the ZF2 module.config.php if I can load instance a object using composer autoloader. The same thing for zend factories, why to use this if I can easily implement a Factory class and call it in a controller?
相关问题
- Views base64 encoded blob in HTML with PHP
- how to define constructor for Python's new Nam
- Laravel Option Select - Default Issue
- PHP Recursively File Folder Scan Sorted by Modific
- Keeping track of variable instances
In completion of @Fge answer iI will show you an example I experimented myself on how service manager can be useful, and when it's not.
I make a dynamic form wich on a few elements I had to add some filters and some validators.
I show you my custom service's method that doi this job for me :
You can see that I use some arrays, and some Zend\Validators. You also see that I use
$this->translator
on each options Array that I pass to those validators. Why I pass the translator ? Let's have a look to the validator :And the abstract Validator
If you use the service manager the
TranslatorAwareInterface
will be instanciated by an initializer. Wich, if you declared the new validator directly in you service, will not be the case, so you have to set it in your options.To be clear up front - the
ServiceLocator
is not amust use
way for creating objects. You still can create objects directly, and in quite a few cases this is a perfectly valid approach.With that being said, there are a few reasons why you want to use the
ServiceLocator
for some objects. Unfortunately the Wikipedia Page on this doesn't help much with understanding the reasons to use a service locator. I found the description and examples here much more useful.For the remainder of this, I'll use the terms
class
andservice
interchangeable. I'll name the class/object requiring a serviceConsumer
, the factory responsible for creating a service afactory
.There is one very important fact to know about service managers. The service name does not need to be a class name. It can be any string (e.g. the services' name).
The major reasons why you want to use a service locator are:
constructions
from the consumer (is it created by a factory or instantiated directly)Re-use services
This is probably the easiest to see. Typically you have a service and want the same instance to be used across your application. Use-cases for this could be anything from a
Configuration
service toCaching Service
.We sure could use a Singleton for making sure that only one instance is created globally - and this would work as well. But this doesn't provide the benefits of the other arguments following.
In Zf2, all services are shared by default. So each time you request a service by name, you will get the same instance. This can be turned of on a per-service level (that's the
shared
config key for in theservice_manager
configuration).Abstract means of creation Ideally, the consumer should not need to know how a required service is to be created. This makes it more decoupled from the required service. All it needs to know, is to say
I require an instance of this service
.Using a service manager, you can achieve this: you ask the service manager to fetch a specific service, But you don't care how the service manager actually creates this. It could be that the service manager instantiates it directly. It could be a factory. The consumer doesn't care - all it only cares about the result, an instance of that service.
The benefit of doing so is that you can replace the mean of creating that service transparently and don't have to update the consumer code to the new way of creating that service.
Decoupling modules
Hiding the way of how a service is created leads to decoupling modules. Let's assume you have two modules
Cache
andUser
. Theuser
module requires aCache
Service from theCache
module. Instead of having to rely on theCache
Module and implementation directly, you hide that fact by a service namedcache
. Theuser
module doesn't care at all how theCache
module creates that service. In fact we could even replace theCache
module with another moduleAdvancedCache
providing the same service, without having to update theUser
module. TheUser
module isn't tied to a particular module - only the the existence of a service namedcache
.Abstract service names
In the previous example, I already introduced this concept. Each service has a global name - a simple string. In many cases that is the class name, but we are not limited to this.
To stick the the previous example of a
cache
service: in here we didn't specify which type of cache theUser
Module actually wants - it doesn't care. It could be anarray
(in-memory) cache, afile
cache, ormemcache
cache.In some other place we decide which cache we want to use globally and assign that concrete implementation to the name of
cache
. All modules requiring thatcache
service now automatically receive that implementation without needing to be updated.In Zf2, this is used quite extensively. Take the
Request
Service for example. In many cases this is an instance of theHttp\Request
. But when using the CLI, this would be anConsole\Request
instead. But when requesting theRequest
service, we literally don't care about which one re receive, as long as they behave the same.Another example for this would be the
Renderer
. Depending on the environment we want to render the output for, we receive a different implementation (HTML/Json/Console usage). But our consumer doesn't need to know which concrete implementation we are rendering for/.Delegators
Delegators can be used to
extend
a factory. I'll leave this out of scope for now though as this is a more advanced use-case. So much be said, you can extend/proxy service creations upon creation time.