zendframework/zend-servicemanager
Abandoned Zend Framework ServiceManager (moved to laminas/laminas-servicemanager). Implements the Service Locator pattern to create and retrieve services/objects via factories and configuration. Includes docs, tests, and PHPBench benchmarks.
#180 adds
explicit support for PSR-11 (ContainerInterface) by requiring
container-interop at a minimum version of 1.2.0, and adding a requirement on
psr/container 1.0. Zend\ServiceManager\ServiceLocatorInterface now
explicitly extends the ContainerInterface from both projects.
Factory interfaces still typehint against the container-interop variant, as changing the typehint would break backwards compatibility. Users can duck-type most of these interfaces, however, by creating callables or invokables that typehint against psr/container instead.
-i or --ignore-unresolved to the shipped
generate-deps-for-config-factory command. This flag allows it to build
configuration for classes resolved by the ConfigAbstractFactory that
typehint on interfaces, which was previously unsupported.ConfigAbstractFactory to allow the config service to be either an
array or an ArrayObject; previously, only array was supported.Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory, which enables a
configuration-based approach to providing class dependencies when all
dependencies are services known to the ServiceManager. Please see
the documentation for details.Zend\ServiceManager\Tool\ConfigDumper, which will introspect a given class
to determine dependencies, and then create configuration for
Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory, merging it with
the provided configuration file. It also adds a vendor binary,
generate-deps-for-config-factory, for generating these from the command
line.Zend\ServiceManager\Tool\FactoryCreator, which will introspect a given class
and generate a factory for it. It also adds a vendor binary,
generate-factory-for-class, for generating these from the command line.Zend\ServiceManager\AbstractFactory\ReflectionBasedAbstractFactory. This
class may be used as either a mapped factory or an abstract factory, and will
use reflection in order to determine which dependencies to use from the
container when instantiating the requested service, with the following rules:
$config type-hinted against array will be injected with the
config service, if present.ServiceManager
classfile, removing potential name resolution conflicts that occurred in edge
cases when testing.ocramius/proxy-manager ^2.0 together with
zendframework/zend-servicemanager.7.0.*.ServiceManager#setFactory() and
ServiceManager#setAlias()zendframework/zend-servicemanager component now provides a
container-interop/container-interop-implementation implementationServiceManager; it now raises a
Zend\ServiceManager\Exception\CyclicAliasException when one is detected,
detailing the cycle detected.Zend\ServiceManager\Test\CommonPluginManagerTrait, which can be used to
validate that a plugin manager instance is ready for version 3.ArrayUtils::merge() routine
as a private method of Zend\ServiceManager\Config.First stable release of version 3 of zend-servicemanager.
Documentation is now available at http://zend-servicemanager.rtfd.org
You can now map multiple key names to the same factory. It was previously
possible in ZF2 but it was not enforced by the FactoryInterface interface.
Now the interface receives the $requestedName as the second parameter
(previously, it was the third).
Example:
$sm = new \Zend\ServiceManager\ServiceManager([
'factories' => [
MyClassA::class => MyFactory::class,
MyClassB::class => MyFactory::class,
'MyClassC' => 'MyFactory' // This is equivalent as using ::class
],
]);
$sm->get(MyClassA::class); // MyFactory will receive MyClassA::class as second parameter
Writing a plugin manager has been simplified. If you have simple needs, you no
longer need to implement the complete validate method.
In versions 2.x, if your plugin manager only allows creating instances that
implement Zend\Validator\ValidatorInterface, you needed to write the
following code:
class MyPluginManager extends AbstractPluginManager
{
public function validate($instance)
{
if ($instance instanceof \Zend\Validator\ValidatorInterface) {
return;
}
throw new InvalidServiceException(sprintf(
'Plugin manager "%s" expected an instance of type "%s", but "%s" was received',
__CLASS__,
\Zend\Validator\ValidatorInterface::class,
is_object($instance) ? get_class($instance) : gettype($instance)
));
}
}
In version 3, this becomes:
use Zend\ServiceManager\AbstractPluginManager;
use Zend\Validator\ValidatorInterface;
class MyPluginManager extends AbstractPluginManager
{
protected $instanceOf = ValidatorInterface::class;
}
Of course, you can still override the validate method if your logic is more
complex.
To aid migration, validate() will check for a validatePlugin() method (which
was required in v2), and proxy to it if found, after emitting an
E_USER_DEPRECATED notice prompting you to rename the method.
A new method, configure(), was added, allowing full configuration of the
ServiceManager instance at once. Each of the various configuration methods —
setAlias(), setInvokableClass(), etc. — now proxy to this method.
A new method, mapLazyService($name, $class = null), was added, to allow
mapping a lazy service, and as an analog to the other various service
definition methods.
Peering has been removed. It was a complex and rarely used feature that was misunderstood most of the time.
Integration with Zend\Di has been removed. It may be re-integrated later.
MutableCreationOptionsInterface has been removed, as options can now be
passed directly through factories.
ServiceLocatorAwareInterface and its associated trait has been removed. It
was an anti-pattern, and you are encouraged to inject your dependencies in
factories instead of injecting the whole service locator.
v3 of the ServiceManager component is a completely rewritten, more efficient implementation of the service locator pattern. It includes a number of breaking changes, outlined in this section.
You no longer need a Zend\ServiceManager\Config object to configure the
service manager; you can pass the configuration array directly instead.
In version 2.x:
$config = new \Zend\ServiceManager\Config([
'factories' => [...]
]);
$sm = new \Zend\ServiceManager\ServiceManager($config);
In ZF 3.x:
$sm = new \Zend\ServiceManager\ServiceManager([
'factories' => [...]
]);
Config and ConfigInterface still exist, however, but primarily for the
purposes of codifying and aggregating configuration to use.
ConfigInterface has two important changes:
configureServiceManager() now must return the updated service manager
instance.toArray(), was added, to allow pulling the configuration in
order to pass to a ServiceManager or plugin manager's constructor or
configure() method.Interfaces for FactoryInterface, DelegatorFactoryInterface and
AbstractFactoryInterface have changed. All are now directly invokable. This
allows a number of performance optimization internally.
Additionally, all signatures that accepted a "canonical name" argument now remove it.
Most of the time, rewriting a factory to match the new interface implies
replacing the method name by __invoke, and removing the canonical name
argument if present.
For instance, here is a simple version 2.x factory:
class MyFactory implements FactoryInterface
{
function createService(ServiceLocatorInterface $sl)
{
// ...
}
}
The equivalent version 3 factory:
class MyFactory implements FactoryInterface
{
function __invoke(ServiceLocatorInterface $sl, $requestedName)
{
// ...
}
}
Note another change in the above: factories also receive a second parameter, enforced through the interface, that allows you to easily map multiple service names to the same factory.
To provide forwards compatibility, the original interfaces have been retained, but extend the new interfaces (which are under new namespaces). You can implement the new methods in your existing v2 factories in order to make them forwards compatible with v3.
The for AbstractFactoryInterface interface renames the method canCreateServiceWithName()
to canCreate(), and merges the $name and $requestedName arguments.
Plugin managers will now receive the parent service locator instead of itself
in factories. In version 2.x, you needed to call the method
getServiceLocator() to retrieve the parent (application) service locator.
This was confusing, and not IDE friendly as this method was not enforced
through the interface.
In version 2.x, if a factory was set to a service name defined in a plugin manager:
class MyFactory implements FactoryInterface
{
function createService(ServiceLocatorInterface $sl)
{
// $sl is actually a plugin manager
$parentLocator = $sl->getServiceLocator();
// ...
}
}
In version 3:
class MyFactory implements FactoryInterface
{
function __invoke(ServiceLocatorInterface $sl, $requestedName)
{
// $sl is already the main, parent service locator. If you need to
// retrieve the plugin manager again, you can retrieve it through the
// servicelocator:
$pluginManager = $sl->get(MyPluginManager::class);
// ...
}
}
In practice, this should reduce code, as dependencies often come from the main service locator, and not the plugin manager itself.
To assist in migration, the method getServiceLocator() was added to ServiceManager
to ensure that existing factories continue to work; the method emits an E_USER_DEPRECATED
message to signal developers to update their factories.
PluginManager now enforces the need for the main service locator in its
constructor. In v2.x, people often forgot to set the parent locator, which led
to bugs in factories trying to fetch dependencies from the parent locator.
Additionally, plugin managers now pull dependencies from the parent locator by
default; if you need to pull a peer plugin, your factories will now need to
pull the corresponding plugin manager first.
If you omit passing a service locator to the constructor, your plugin manager will continue to work, but will emit a deprecation notice indicatin you should update your initialization code.
It's so fast now that your app will fly!
AbstractPluingManager and introduces
InvokableFactory to help forward migration to version 3.ServiceManager::setFactory() to remove
references to abstract factories.ServiceManager to implement the container-interop interface,
allowing interoperability with applications that consume that interface.$this in a closure is the invoking object when created within a method). It
also removes several [@requires](https://github.com/requires) PHP 5.4.0 annotations.How can I help you explore Laravel packages today?