Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ZF2 Deprecated: ServiceManagerAwareInterface

Today i updated my project and i got this warning :

Deprecated: ServiceManagerAwareInterface is deprecated and will be removed in version 3.0, along with the ServiceManagerAwareInitializer. Please update your class X to remove the implementation, and start injecting your dependencies via factory instead

I have some main Base classes that implements the ServiceManagerAwareInterface and multiple classes that extends these base classes.

So is it a good practice to create on extra factory class for each of these classes ? or is it better to use 1 AbstractFactory for each module and initiate the classes in there ?

Dose using the AbstractFactory impact performance ?

Whats the best practice for injecting a single(or 2) shared dependency in many classes?

UPDATE : Even tho that i accepted @AlexP's answer but i have some concerns about providing dependencies throw constructor. Imagine this scenario : I have a controller with couple of actions, lest say ActionA needs ServiceZ and ActionB needs ServiceY and ServiceX, and ServiceX is also depends on ServiceM and ServiceN. Now every time i am calling ActionA my controller in initiated with all of these services, but ActionA only needs 1 service where my controller is loaded with 5 services.... is this a good practice ? is this the right way do to it ? wouldn't this have bad performance, since on every request services are being initiated that we won't use at all during that request ?

Right now i am allowing each service/controller to take care of its own needs and load services when it needs them.

This way i won't have to initiate multiple services that i wont use and i don't need o know the services dependencies to use them. I know this is not accepted as best practice but the code is clean and i prefer to sacrifice "Best Practice" to have better performance.

Appreciate anyone's input on this.

like image 492
Exlord Avatar asked Mar 19 '16 10:03

Exlord


1 Answers

A factory per service is normally an ideal goal; however there are many cases when you have similar classes that have similar dependencies and creating that number of factories for each one would be unnecessary and difficult to maintain.

An abstract factory solves the multiple factories issue by matching each service it can create by name and then return a new instance using some custom configuration.

This introduces some issues.

  • Calls to $serviceManager->get() or $serviceManager->has() will require the abstract factory to check it can create the service using its canCreateServiceWithName() method; with multiple abstract factories this could add a considerable performance overhead.

  • The abstract factory has no concept of a service 'alias'; functionality offered by the service manager. The implementation requires you match on the $requestedName of the service. This is an issue if you have calls for services using both the the full service name and an alias.

  • Abstract factories are tightly coupled to the ZF2 framework.

The roadmap for the framework is very much focused on addressing these issues, ZF3 still offers the abstract factories however it also introduces some improvements in factory design to encourage reusability which you can already take advantage of.

Note that the factory now accepts an additional required argument, $requestedName; v2 already passed this argument, but it was not specified in the interface itself. Because factories now can expect to receive the service name, they may be re-used for multiple services, largely replacing abstract factories in version 3.

So we can already use standard factories multiple times for similar services (in ZF2).

A very simple example on how to create similar service with one factory.

'service_manager' => [
    'factories' => [
        'My\Service\Foo' => 'My\Factory\SharedFactory',
        'My\Service\Bar' => 'My\Factory\SharedFactory',
        'My\Service\Baz' => 'My\Factory\SharedFactory',
    ],
],

namespace My\Factory;

class SharedFactory
{
    public function __invoke($serviceLocator, $name, $requestedName)
    {
        if (! class_exists($requestedName)) {
            throw new ServiceNotCreatedException("$requestedName could not be found!");
        }

        return new $requestedName(
            $serviceLocator->get('SomeDependacy1'),
            $serviceLocator->get('SomeDependacy2')
        );
    }
}

You could easily extend this to load custom service configuration using the $requestedName argument to add even greater flexibility.

like image 106
AlexP Avatar answered Oct 23 '22 03:10

AlexP