The PSR-7 standard, which describes common HTTP message interfaces, is a big step towards interoperability across different PHP libraries. The standard was introduced not long ago, but you can already use libraries compatible with this recommendation within your Symfony-based application.
Web applications nowadays may be very complex, but technically they all do the same thing: take a HTTP request, perform some actions, and return a HTTP response. A long time ago, a typical PHP application operated directly on global arrays such as $_GET or $_POST. Over the years, many frameworks have tried to solve the problem of normalising a request and handling a response.
Symfony2 brought the HttpFoundation component to the community some time ago. The component, containing Request and Response classes abstracting HTTP messages, became widely used and beneficial for other big projects such as Laravel, Drupal 8, phpBB, eZ Platform, and Sylius, to name just a few.
But the situation wasn’t perfect. There was no standard across the PHP world, with lots of different frameworks using their own implementations for dealing with HTTP.
A step toward more homogeneity was achieved when the PHP Framework Interop Group accepted PSR-7 in May 2015. This recommendation describes common HTTP message interfaces. The biggest benefit the PHP community gets from the standard is a potential for interoperability across different PHP libraries.
You can already use libraries compatible with this recommendation within your Symfony-based application thanks to the Symfony PSR-7 Http Message Bridge.
Symfony PSR-7 HTTP Message bridge
The Symfony kernel is responsible for handling a HttpFoundation Request and returning a Response object defined in the same component. Because of the backwards compatibility promise, the Symfony kernel won’t accept PSR-7 requests returning PSR-7 responses before Symfony 4.0. However, just a couple weeks after PSR-7 was accepted, Symfony introduced the PSR-7 bridge, “which converts HttpFoundation objects from and to objects implementing HTTP message interfaces defined by the PSR-7” . It also provides a native support for Zend Diactoros, which is a PSR-7 HTTP Message implementation.
To convert a HttpFoundation Request to a Zend Diactoros ServerRequest implementing Psr\Http\Message\ServerRequestInterface, you will need to use a DiactorosFactory:
Similarly, if you want to convert HttpFoundation Response to a Zend Diactoros Response implementing PSR-7 Psr\Http\Message\ResponseInterface, you will use the same factory object:
Converting the other way around, objects implementing PSR-7 interfaces to HttpFoundation, is as simple as the above: you will just need to use a HttpFoundationFactory instead.
How to use PSR-7 request and response in controller
If you want to use request and response objects, implementing PSR-7 interfaces in your controllers, you don’t have to convert HttpFoundation ones yourself. TheSensioFrameworkBundle comes with a simple event listener which does the trick for you.
PsrResponseListener checks whether the returned class implements Psr\Http\Message\ResponseInterface and uses HttpFoundationFactory, to convert it to the HttpFoundation Response object. This means that if you work with PSR-7 interfaces in your controller, you no longer have to worry about returning a HttpFoundation Response object from your method.
You can also typehint your method argument to the ServerRequestInterface thanks to the PsrServerRequestParamConverter.
Summarising, the controller compatible with PSR-7 interfaces, which prints `Hello world` (or `Hello Inviqa` if you pass `Inviqa` in a query string), might look like this one:
All you need to do is to install required dependencies via composer:
If you are not using the Symfony standard edition, you need to register the SensioExtraFrameworkBundle in your Kernel class:
One of the big benefits of PSR-7 is the ability to use so-called middlewares. These are single responsibility code snippets allowing to do something with the request, call another middleware and eventually return a response. However, PSR-7 doesn’t standardise exactly how middleware should look. A common approach is to provide a callable with the signature:
or using a class:
If you are interested in creating middleware applications, you might also be interested in Zend Expressive, RelayPHP or Slim3.
The PSR-7 standard is a step in a good direction - allowing developers to write PHP libraries which can be reused in many different projects. The Symfony PSR-7 bridge currently has some performance issues when dealing with large and streamed requests and responses. However, it is a great start for the Symfony community, and the PSR-7 subject will definitely evolve in the future.
About the author
Marek Pietrzak is a Software Engineer at Inviqa in Manchester. He is a PHP, Symfony and TDD enthusiast, as well as a certified Symfony Developer and Zend Certified PHP Engineer. You can find him on Twitter or Github.