Build middleware applications with Zend Framework 3

by Enrico Zimuel / @ezimuel

Senior Software Engineer
Zend Technologies, a Rogue Wave Company

About me

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

We almost done, working on docs and the new web site.

The plan is to release the full ZF3 packages on June 2016.


A function that gets a request and generates a response

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

The Middleware onion


Shared HTTP Message Interfaces

HTTP Request

// $request instanceOf Psr\Http\Message\RequestInterface
$method     = $request->getMethod();
$accept     = $request->getHeader('Accept');
$path       = $request->getUri()->getPath();
$controller = $request->getAttribute('controller');

HTTP Response

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

A PSR-7 Middleware Class

Use an additional callable during the invoke ($next)

use Psr\Http\Message\RequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;

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


  • 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;


Piping Middleware

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

// 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


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 = []);


  • 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
  • The FinalHandler is executed if:
    • the middleware stack is exhausted, and no middleware has returned a response
    • an error has been passed via $next(), but not handled by any 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');
$final = new TemplatedErrorHandler($plates, 'error::404', 'error::500');

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

Skeleton application

Getting started

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

Run the skeleton app

$ composer serve

Open your browser at http://localhost:8080

Skeleton tree

├── config
│   └── autoload
├── data
│   └── cache
├── public
├── src
│   └── App
│       └── Action
├── templates
│   ├── app
│   ├── error
│   └── layout
└── test


The application configuration files, including:

  • the registered services;
  • the middleware pipeline;
  • the routes;
  • the template file paths;
  • the error handler;

Example of route config


return [
    'dependencies' => [
        'factories' => [
            App\Action\FooAction::class => App\Action\FooFactory::class,

    'routes' => [
            'name' => 'home',
            'path' => '/',
            'middleware' => App\Action\FooAction::class,
            'allowed_methods' => ['GET'],

Front controller


// Delegate static file requests back to the PHP built-in webserver
if (php_sapi_name() === 'cli-server'
    && is_file(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))
) {
    return false;

require 'vendor/autoload.php';

/** @var \Interop\Container\ContainerInterface $container */
$container = require 'config/container.php';

/** @var \Zend\Expressive\Application $app */
$app = $container->get(\Zend\Expressive\Application::class);

Service container


use Zend\ServiceManager\Config;
use Zend\ServiceManager\ServiceManager;

// Load configuration
$config = require __DIR__ . '/config.php';

// Build container
$container = new ServiceManager();
(new Config($config['dependencies']))->configureServiceManager($container);

// Inject config
$container->setService('config', $config);

return $container;

A Middleware Action Factory


namespace App\Action;

use Interop\Container\ContainerInterface;
use Zend\Expressive\Template\TemplateRendererInterface;

class FooFactory
  public function __invoke(ContainerInterface $container)
    $template = ($container->has(TemplateRendererInterface::class))
                ? $container->get(TemplateRendererInterface::class)
                : null;
    return new FooAction($template);

A Middleware Action


namespace App\Action;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Expressive\Template\TemplateRendererInterface;

class FooAction
  protected $template;

  public function __construct(TemplateRendererInterface $template = null)
    $this->template = $template;

  public function __invoke(
    ServerRequestInterface $request,
    ResponseInterface $response,
    callable $next = null
  ) {
    $data = [];
    // get the data to print in the template
    return new HtmlResponse($this->template->render('app::foo', $data));


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.