Question

In my ZF2 application, I use Zend\Di\Di to create all my class instances. The DI definitions are scanned using Zend\Di\Definition\CompilerDefinition and cached using APC. This avoids scanning the classes at runtime using slow reflection. If there is an exception during instance creation (because of outdated DI definitions), the code is rescanned, the definitions are cached, and the instance is created again.

This is very convenient during development, since no factory methods/closures have to be written or changed for new classes or changed constructors. My constructors follow a certain convention (only type-hinted arguments and a singe $params array) to ensure that dependency injection works without specifying additional constructor params.

Up till now, this performs nicely, avoids bugs (no outdated factory methods), and speeds up development. However, the scanned definitions are currently 1.8MB (serialized array) in APC, and growing. Since they have to be loaded from cache upon every request, I fear that memory will be exhausted if there are too many requests in a short time. I have no load testing setup to simulate this, though.

I'm aware that the recommended way is to use Zend\ServiceManager and write factory closures for every class, instead of using Zend\Di\Di. But I imagine this is a lot of work and quite annoying during development.

Do you recommend refactoring to Zend\ServiceManager in this situation?

Was it helpful?

Solution 2

This is exactly what I exposed in my blogpost about Zend\Di and RAD.

While Zend\Di is good for development, it is a huge memory and performance bottleneck in production. Even if you cache definitions, it still uses ReflectionClass and call_user_func_array() to manipulate your instances. It also has to perform a lot of surrounding operations that are necessary to align injection parameters: just take a look at the number of calls to array_merge during instantiation of an object via Zend\Di.

I wrote a module to handle compiling of Zend\Di\Di instance managers to closures: OcraDiCompiler. It needs a bit of cleanup, but its job is to generate code factory/closures by tracing instantiation logic of Zend\Di internals. If you want to "revive" it a bit, I'd be glad to help out on that, since it's in my TODO list, but with low priority right now.

Anyway, moving instantiation logic to factories/closures through the ServiceManager is not as much work as you'd expect, so don't be scared and give it a try: you may like it.

OTHER TIPS

I have written a ZF2 module to help you solve this problem: https://github.com/aimfeld/ZendDiCompiler

ZendDiCompiler is a Zend Framework 2 module that uses auto-generated factory code for dependency-injection. It saves you a lot of work, since there's no need anymore for writing Zend\ServiceManager factory closures and keeping them up-to-date manually.

ZendDiCompiler scans your code (using Zend\Di) and creates factory methods automatically. If the factory methods are outdated, ZendDiCompiler updates them in the background. Therefore, you develop faster, avoid bugs due to outdated factory methods, and experience great performance in production!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top