Other containers rely on auto wiring and auto discovery in order to know which dependencies need to be injected on every service, and I think that leads to errors when an application grows.

I like zend-servicemanager because it is explicit, and you are always in control of what's done, without loosing flexibility in the process.

However, I have to recognize that it comes with a prize.

Factories everywhere

Since this container expects you to define factories for every service, you usually end up writing, testing and maintaining a lot of factories that doesn't add value to the application.

That's why it is so important to properly reuse factories when possible, not only because you will have to maintain less classes, but because the ServiceManager will instantiate less objects at runtime when it can reuse a factory.

This article is born because of the question of a reader of this blog, which asked me what did I mean with the "redundancy mitigated by reusing same factory" sentence, in one of my Zend Expressive articles.

Using ConfigAbstractFactory

The zend-servicemanager v3.2 introduced a built-in factory that can inject dependencies on services based on configuration.

This is probably one of the better ways to reuse factories (indeed, you won't have to write any factory, since this one is included in the package).

In 80% of the cases (if not more), a factory basically consists on grabbing some dependencies from the container, and creating a new instance of an object where those dependencies are injected. In those cases the ConfigAbstractFactory is perfect.

When using this factory, you just need to define a configuration block where you define the service names on which every other service depends.

Using ReflectionBasedAbstractFactory

This factory works similarly to the previous one, but instead of discovering the dependencies to inject based on a configuration array, it uses reflection on requested service.

This has the small advantage that you don't have to specify the dependencies for every service. However, reflection is very inefficient, so this factory is not suited for production, but only for prototyping purposes.

Also, you need to register services with the same type used in the requested service constructor, so you can't type hint to an interface and then inject a service which is registered with an implementation name, or a string which is not even a class name.

Using acelaya/zsm-annotated-services package

Some time ago (when the ConfigAbstractFactory didn't exist yet), I created the acelaya/zsm-annotated-services package, which provides one factory that can discover the list of dependencies of a service based on an @Inject annotation in its constructor, instead of using a configuration array.

However, if I were you, I would choose the ConfigAbstractFactory over this one, because using annotations couples the configuration with the service.

Conclusion

The problem of defining several factories is usually the main argument I hear against using this component, but as you can see, there are several approaches to deal with it, without loosing control over your code base or depending on black magic.

There are probably other options that I've missed here, so if you know any other approach, just comment this post and I will gladly add it.