Migration to Expressive 2.2

Version 2.2 exists to message deprecated functionality, and to provide backports of functionality from version 3.0 as it makes sense. In most cases, your code should continue to work as it did before, but may now emit deprecation notices. This document details some specific deprecations, and how you can change your code to remove the messages, and, simultaneously, help prepare your code for version 3.

Config providers

The zend-expressive and zend-expressive-router packages now expose config providers. These are dedicated classes that return package-specific configuration, including dependency information. We suggest you add these to your application's configuration. Add the following two lines in your config/config.php file, inside the array passed to the ConfigAggregator constructor:


The command ./vendor/bin/expressive migrate:expressive-v2.2 will do this for you.

Routing and dispatch middleware

In previous releases of Expressive, you would route your routing and dispatch middleware using the following dedicated methods:


These methods are now deprecated, and will be removed in version 3.0.

Instead, you should use pipe() with the following services:


The command ./vendor/bin/expressive migrate:expressive-v2.2 will do this for you.

This also means you can easily replace these middleware with your own at this time!

Routing and dispatch constants

If you are using configuration-driven routes, you are likely using the constants Zend\Expressive\Application::ROUTING_MIDDLEWARE and DISPATCH_MIDDLEWARE to indicate the routing and dispatch middleware, as follows:

'middleware_pipeline' => [

In the above section, we detailed deprecation of the methods pipeRoutingMiddleware() and pipeDispatchMiddleware(); the constants above are the configuration equivalent of calling these methods, and are similarly deprecated.

Change these entries to use the same syntax as other pipeline middleware, and have the middleware key indicate the appropriate middleware class as follows:

'middleware_pipeline' => [
        'middleware' => \Zend\Expressive\Router\Middleware\RouteMiddleware::class,
        'middleware' => \Zend\Expressive\Router\Middleware\DispatchMiddleware::class,

Implicit HEAD and OPTIONS middleware

These middleware have moved to the zend-expressive-router package. While they still exist within the zend-expressive package, we have added deprecation notices indicating their removal in v3. As such, update either of the following statements, if they exist in your application:




The command ./vendor/bin/expressive migrate:expressive-v2.2 will do this for you.

Response prototypes

A number of services expect a response prototype which will be used in order to generate and return a response. Previously, we did not expose a service for this, and instead hard-coded factories to create a zend-diactoros Response instance when creating a service.

In version 3, we plan to instead compose a response factory in such services. This is done to ensure a unique response prototype instance is generated for each use; this is particularly important if you wish to use such services with async web servers such as Swoole, ReactPHP, AMP, etc.

To prepare for that, Expressive 2.2 does the following:

The various factories that hard-coded generation of a response previously now pull the ResponseInterface service and, if it is callable, call it to produce a response, but otherwise use the return value.

This change should not affect most applications, unless they were defining a ResponseInterface service previously. In such cases, ensure your factory mapping has precedence by placing it in a config/autoload/ configuration file.

Double-Pass middleware

Double-pass middleware refers to middleware that has the following signature:

function (
    ServerReqeustInterface $request,
    ResponseInterface $response,
    callable $next
) : ResponseInterface

where $next will receive both a request and a response instance (this latter is the origin of the "double-pass" phrasing).

Such middleware was used in v1 releases of Expressive, and we have continued to support it through v2. However, starting in v3, we will no longer allow you to directly pipe or route such middleware.

If you need to continue using such middleware, you will need to decorate it using Zend\Stratigility\Middleware\DoublePassMiddlewareDecorator(). This decorator class accepts the middleware and a response prototype as constructor arguments, and decorates it to be used as http-interop middleware. (In version 3, it will decorate it as PSR-15 middleware.)

The zend-stratigility package provides a convenience function, Zend\Stratigility\doublePassMiddleware(), to simplify this for you:

use Zend\Diactoros\Response;
use function Zend\Stratigility\doublePassMiddleware;

// Piping:
$app->pipe(doublePassMiddleware($someMiddleware, new Response()));

// Routing:
$app->get('/foo', doublePassMiddleware($someMiddleware, new Response()));

Other deprecations

The following classes, traits, and instance methods were deprecated, and will be removed in version 3:


In addition to the above deprecations, we also provide a new class, Zend\Expressive\Container\ApplicationConfigInjectionDelegator. This class services two purposes:

To enable the delegator as a delegator factory, add the following configuration to a config/autoload/ configuration file, or a configuration provider class:

'dependencies' => [
    'delegators' => [
        \Zend\Expressive\Application::class => [

To manually inject an Application instance, you can do the following:

use Zend\Expressive\Container\ApplicationConfigInjectionDelegator;

// assuming $config is the application configuration:
ApplicationConfigInjectionDelegator::injectPipelineFromConfig($app, $config);
ApplicationConfigInjectionDelegator::injectRoutesFromConfig($app, $config);

These changes will be forwards-compatible with version 3.