Build middleware applications with Zend Framework 3

by Enrico Zimuel / @ezimuel

Senior Software Engineer
Zend Technologies, a Rogue Wave Company

About me

Table of contents

  • ZF3: latest news
  • Middleware applications in PHP
  • PSR-7 standard
  • Middleware with zend-expressive
  • A skeleton application

Zend Framework 3

  • 50+ separate components on github
  • Support PSR-7 standard
  • Middleware and MVC patterns
  • Performance improvement: 4x faster than ZF2!
  • Optimized for PHP 7, but supporting PHP 5.5 onwards
  • Stats: 10,269 stars, 8,167 forks, 124 repos, 699 contributors

ZF3 roadmap

  • Performance improvement
  • PSR-7 support
  • New middleware components: Stratigility, Expressive, MiddlewareListener (MVC)
  • Enable forward compatibility with version 3
  • Updated documentation and website
  • Code refactor of MVC


A function that gets a request and generates a response

function ($request, $response) {
    // manipulate $request to generate a $response
    return $response;

Build a middleware workflow

1) Passing middleware to other middleware:

class Middleware
    protected $middleware;

    public function __construct(callable $middleware) {
        $this->middleware = $middleware;

    public function __invoke($request, $response) {
        // do something before
        call_user_func($this->middleware, $request, $response);
        // do something after

Build a middleware workflow

2) Use an additional callable during the invoke ($next)

class Middleware
    public function __invoke($request, $response, callable $next = null) {
        // do something before
        if ($next) {
            $next($request, $response);
        // do something after

The Middleware onion

HTTP is the foundation of the web

  • A client sends a request
  • A server returns a response

HTTP messages


GET /path HTTP/1.1
Accept: application/json


HTTP/1.1 200 OK
Content-Type: application/json


Frameworks model messages

But every framework does it differently.

$method = $request->getMethod();
$method = $request->getRequestMethod();
$method = $request->method;


Shared HTTP Message Interfaces


$method     = $request->getMethod();
$accept     = $request->getHeader('Accept');
$path       = $request->getUri()->getPath();
$controller = $request->getAttribute('controller');


$response->getBody()->write('Hello world!');
$response = $response
  	->withStatus(200, 'OK')
  	->withHeader('Content-Type', 'text/plain');


  • PSR-7 support (using zend-diactoros)
  • Middleware using a callable ($next):
    function ($request, $response, $next)
  • Piping workflow (using zend-stratigility)
  • Features: routing, container-interop, templating, error handling
  • Stable version 1.0 (28 Jan 2016)

Components layer

Flow overview

Basic example

use Zend\Expressive\AppFactory;

require 'vendor/autoload.php';

$app = AppFactory::create();

$app->get('/', function ($request, $response, $next) {
    $response->getBody()->write('Hello, world!');
    return $response;



namespace Zend\Expressive\Router;
use Psr\Http\Message\ServerRequestInterface as Request;

interface RouterInterface
    public function addRoute(Route $route);
    public function match(Request $request);
    public function generateUri($name, array $substitutions = []);

Routing example

// $app is an instance of Zend\Expressive\AppFactory

$app->get('/', function ($request, $response, $next) {
    $response->getBody()->write('Hello, world!');
    return $response;

Piping Middleware

// $app is an instance of Zend\Expressive\AppFactory

// Executed in all the requests
$app->pipe('middleware service name');

// Pipe to a specific URL
$app->pipe('/api', $apiMiddleware);
$app->pipe('/api', 'middleware service name');

// Error handler
$app->pipeErrorHandler('error handler service name');
$app->pipeErrorHandler('/api', 'error handler service name');

Using a Service Container

use Zend\Expressive\AppFactory;
use Zend\ServiceManager\ServiceManager;

$container = new ServiceManager();

$container->setFactory('HelloWorld', function ($container) {
    return function ($req, $res, $next) {
        $res->write('Hello, world!');
        return $res;

$app = AppFactory::create($container);
$app->get('/', 'HelloWorld');

We support container-interop


  • While Expressive does not assume templating is being used, it provides a templating abstraction.
  • Default adapters: Plates, Twig, Zend-View

namespace Zend\Expressive\Template;

interface TemplateRendererInterface
    public function render($name, $params = []);
    public function addPath($path, $namespace = null);
    public function getPaths();
    public function addDefaultParam($templateName, $param, $value);

Error Handling

  • Expressive provides error handling out of the box, via zend-stratigility's FinalHandler
  • This pseudo-middleware is executed in the following conditions:
    • If the middleware stack is exhausted, and no middleware has returned a response
    • If an error has been passed via $next(), but not handled by any error middleware

Templated Errors

use Zend\Expressive\Application;
use Zend\Expressive\Plates\PlatesRenderer;
use Zend\Expressive\TemplatedErrorHandler;

$plates = new PlatesRenderer();
$plates->addPath(__DIR__ . '/templates/error', 'error');
$finalHandler = new TemplatedErrorHandler(

$app = new Application($router, $container, $finalHandler);

Using Whoops

Skeleton application

Getting started

$ composer create-project zendframework/zend-expressive-skeleton <path>

Run the skeleton app

$ composer serve

You can browse to http://localhost:8080

Skeleton source code

A brief look at the source code...


Rate this talk at

More info:

Contact me: enrico [at]

Follow me: @ezimuel

Creative Commons License
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.