Zend DI 3.0 is here!

Zend DI is a ZendFramework component, that provides auto-wiring capabilities for IoC containers. But the version 2.x had some mayor performance-drawbacks.
For version 3.0 we thought it would be a nice idea to get rid of these drawbacks…

Why we did it

Defining services in ZendServicemanager requires you to implement a factory for every instance you want to consume. For classes without dependencies, this is no problem at all, the ServiceManager provides setInvokableClass() for this case, but if classes consume dependencies, this requires writing simple factories that pass $container->get(InterfaceName::class) to the constructor most of the time.

A solution that provides automatic wiring for such simple cases would be great. Indeed there is one: Zend DI. But the version 2.x of this component adds performance penalties, inconsistencies and error-prone instantiation to your code.
Also, it is not recommend to use this in production…

Therefore one of our senior developers – who is also one of the ZendFramework experts in our team – decided to re-factor this component to provide a solid and production-ready solution.
In the true spirit of Open Source we decided to give it back to the community, which was accepted and published as the next major release of the component.
(*Yeah!*)

Why you should use it

So what’s the fuss about and why should you bother using it?
This is easy to answer: it is designed to assist you when implementing a ZendFramework Application (whether MVC or Expressive).

Let me give you an example: Assuming you are going to develop an expressive application that will use Doctrine as persistence framework, you will most likely consume the object manager in some classes (e.g. a Middleware to handle authentication).

So you would have something like this:


use Doctrine\Common\Persistence\ObjectManager;

class MyMiddleware
{
    public function __construct(ObjectManager $om)
    { /* ... */ }
}

class MyAction
{
    public function __construct(ObjectManager $om, SomeOtherService $foo)
    { /* ... */ }
}

Let’s assume you already have configured a service called „Doctrine\Common\Persistence\ObjectManager“ (e.g. an instance of doctrine ORM’s EntityManager) and another service called „SomeOtherService“.

So you now have to write a Service factory for each class to provide it via Zend ServiceManager:


use Doctrine\Common\Persistence\ObjectManager;
use Psr\Container\ContainerInterface;

class MyMiddlewareFactory
{
    public function __invoke(ContainerInterface $container)
    {
        return new MyMiddleware($container->get(ObjectManager::class));
    }
}

class MyActionFactory
{
    public function __invoke(ContainerInterface $container)
    {
        return new MyAction(
            $container->get(ObjectManager::class),
            $container->get(SomeOtherService::class)
        );
    }
}

You also have to create new factories for each new class you add. Even though the fact you can recycle factories like this, it will require another factory as soon as dependencies on the class change:


use Doctrine\Common\Persistence\ObjectManager;
use Psr\Container\ContainerInterface;

class ProvideObjectManagerFactory
{
    public function __invoke(ContainerInterface $container, $classname)
    {
        return new $classname($container->get(ObjectManager::class));
    }
}

And don’t forget as for best practices you should test your factories …

Now doing this rather trivial stuff seems like a waste of time!

It’s relatively clear that in general the ObjectManager (as shown in the example) should be the configured service with the class or interface name from the service manager – so let’s automate it with Zend DI 3!

At first, we will install the component with composer:

composer install zendframework/zend-di

When you are using ZendFramework’s component installer, it will take care of configuring the integration into MVC or Expressive for you. If not – and we’re assuming expressive in this example – there is a config provider that contains the required configuration: Zend\Di\ConfigProvider. For MVC there is a module available: Zend\Di\Module

Now after Zend DI is in place, you can get rid of the factories mentioned above and directly consume your class.

Zend DI will take care of injecting the ObjectManager instance:


use Doctrine\Common\Persistence\ObjectManager;

class MyMiddleware
{
    public function __construct(ObjectManager $om)
    { /* ... */ }
}

class MyAction
{
    public function __construct(ObjectManager $om, SomeServiceInterface $foo)
    { /* ... */ }
}

// No need for a factory now
$serviceManager->get(MyMiddleware::class);

But what if my class consumes an Interface as a dependency instead of a concrete class? The answer is pretty simple: Alias the interface in the service manager configuration. Adding the alias is enough.

The Concrete class will be instantiated by zend-di automatically:

/* part of the zend-servicemanager config: */
return [
    'aliases' => [
        SomeServiceInterface::class => SomeServiceImplementation::class,
        // But you can also alias to services provided by a factory as usual:
        ObjectManager::class => 'doctrine.orm.entity_manager.default',
    ],
];


So it’s simple math: without Zend DI 3 you need one factory per service, with Zend DI 3 you need none (best case) or just a small set of factories for complex cases.

How to get it in production

But what about performance?
…all dependencies are auto-wired at runtime at the cost of performance!

And this is why it comes with a code generator that allows you to resolve dependencies and generate factories ahead of time (AoT).

The official documentation shows how to implement this in detail.

By adding this feature to our project, we improve the performance drastically. The service manager now uses pre-generated factories without lookups to the abstract AutowireFactory or runtime wiring.

Before finally deploying the code to production we can improve performance even further by updating our autoloader with the -o option (Optimize by building class maps):

composer dump-autoload -o

How to use it with older PHP versions

Since newer ZendFramework component releases will drop support for PHP versions before 7.1, you may not be able to use Zend DI 3.x with these PHP versions. But we’ve got you covered. We created a PHP 5.6+ compatible backport on Github that you can use to benefit from these changes and make your code future-proof. When you are ready to upgrade to PHP 7.1 or later, you can then seamlessly switch to the official zend-di.

Please be aware that this backport is not an official part of ZendFramework.

Der Stand von PHP in 2017

In der akutellen „Developer Pulse“-Studie der Firma Rogue Wave Software wurden mehr aus 1200 Enwickler befragt. Dabei ging es vor allem um die Themen PHP7, Anwendungssicherheit und Entwicklungsmethodik. Eine besondere Rolle spielte  auch die Frage nach der Reife des „DevOps“-Modells.
Aus den Ergebnissen der Umfrage entstand eine interessante Info-Grafik. Darin sind die aktuellen Trends im PHP-Bereich gut erkennbar.

Informative Infografik rund um die Themen PHP7, Anwendungssicherheit, Entwicklungsmethodik. und die Reife des "DevOps"-Modells.

Infografik zum Stand von PHP in 2017

Die Hauptergebnisse im Überblick

Einige Erkenntnisse aus der diesjährigen Studie sind besonders interessant:

  • Über 50% der Befragten planen, innerhalb des nächsten Jahres auf PHP 7.x umzustellen. Das ist eine außerordentlich schnelle Akzeptanz der neuen Version.
  • Als größte Sicherheitsbdrohung werden die Schwachstellen im benutzerdefinierten Code empfunden
  • 21% der Befragten haben bereits eine Form von Continuous Delivery (CD) implementiert. Viele andere nutzen zumindest teilweise Automatisierungs-Technologien (wie CI, Testautomatisierung, Freigabeautomatisierung und Bereitstellungsautomatisierung).

Zur Herkunft der Developer-Pulse Studie

Rogue Wave führt mit der jährlichen Studie eine Tradition fort, die die Firma Zend im Jahre 2011 gestartet hatte. Dabei wurden in den vergangenen Jahren regelmäßig bis zu 4000 Entwickler nach Ihrer Einschätzung zu bestimmten Technologietrends befragt.

Die Datenbasis der aktuellen Umfrage war mit 1200 Teilnehmern etwas kleiner. Dennoch werfen die Aussagen ein durchaus repräsentatives Licht auf die aktuellen Themen im Umfeld der Webentwicklung mit PHP.

Rogue Wave erwarb die Firma Zend Technologies Inc. im Oktober 2015. Damit wurde der Anbieter von Entwicklungstools zum Technologieführer im PHP-Bereich. In den Jahren zuvor hatte Zend die Programmiersprache bereits erfolgreich weiterentwickeilt. So war es den beiden Hauptentwicklern Zeev Suraski und Andi Gutmans gelungen, sie aus der Nische der Scriptsprachen zu holen. Heute werden einige der größten Enterprise Anwendungen damit betrieben, so zum Beispiel Facebook, Yahoo, Wikipedia oder WordPress.