PSR-7 Support in Symfony is Here

Less than 2 weeks ago, the PHP community roundly accepted PSR-7, giving PHP a common set of HTTP Message Interfaces. This has huge potential for interoperability and standardization across all of PHP. This is especially true for middleware: functions that hook into the request-response process. In the future, a middleware written around these new interfaces could be used in any framework.

Introducing the PSR HTTP Message Bridge

Today, a huge number of projects use Symfony's Request and Response classes (via the HttpFoundation component), including Laravel, Drupal 8 and StackPHP. This has given us a base for HTTP Message standardization over the last 4 years, before the community was ready to discuss an official interface. Promoting interoperability is at the core of Symfony's philosophy.

For that reason, we're thrilled to announce the 0.1 release of the PSR HTTP Message Bridge: a library that can convert Symfony Request and Response objects to PSR-7 compatible objects and back. This means that once there are middleware written for PSR-7, applications using HttpFoundation will be compatible.

Converting from a PSR-7 object to HttpFoundation is as easy as this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;

$httpFoundationFactory = new HttpFoundationFactory();

// convert a Request
// $psrRequest is an instance of Psr\Http\Message\ServerRequestInterface
$symfonyRequest = $httpFoundationFactory->createRequest($psrRequest);

// convert a Response
// $psrResponse is an instance of Psr\Http\Message\ResponseInterface
$symfonyResponse = $httpFoundationFactory->createResponse($psrResponse);

You can also convert from an HttpFoundation object to PSR-7. For this, the bridge uses Diactoros - an early PSR-7 implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$psr7Factory = new DiactorosFactory();

// convert a Request
$symfonyRequest = Request::createFromGlobals();
$psrRequest = $psr7Factory->createRequest($symfonyRequest);

// convert a Response
$symfonyResponse = new Response('Content');
$psrResponse = $psr7Factory->createResponse($symfonyResponse);

This allows projects to take advantage of PSR-7 immediately, but without breaking backwards compatibility. That's really important: Symfony has a proud backwards compatibility promise that won't be broken.

Thanks a lot to dunglas (a core team member), who did a lot of the initial work on this library. Documentation is in progress and the bridge currently has some edge cases related to large request and response bodies. But this is a fantastic start, and we're thrilled about it.

RequestInterface and ResponseInterface in the Symfony Framework

In the Symfony Framework, a controller usually receives Symfony's Request object and returns a Symfony Response object. But now, you can choose to receive and return PSR-7 Request and Response objects instead, thanks to a small patch to the SensioFrameworkExtraBundle:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace AppBundle\Controller;

use Psr\Http\Message\ServerRequestInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Zend\Diactoros\Response;

class DefaultController extends Controller
{
    public function indexAction(ServerRequestInterface $request)
    {
        // Interact with the PSR-7 request

        $response = new Response();
        // Interact with the PSR-7 response

        return $response;
    }
}

This is available in the latest release of SensioFrameworkExtraBundle, which is compatible with every maintained version of Symfony (2.3+). So if this is something you want to do in your controllers, you can start doing it immediately!

Comments

That's great news! I'm really glad to see that the PHP community is starting to work on common tools! There's no need to reinvent the wheel all the time.

As always - thanks for your great work! :)
Could you say more about the performance penalties due to usage of the bridge to transform the Symfony Requests to PSR-7 Requests and PSR-7 Responses to Symfony Responses?
Amazing work, thanks for the effort!
Good job. Thank you!
@Thomas I don't have any data on that yet. For most cases, it should be minimal, especially since the conversion will likely only happen once per request, or at most twice (if you're converting back and forth). The work to convert is quite minimal, but it will be something nice to profile with Blackfire.

There are 2 cases where performance would be an issue (at least right now): converting large request/response body streams and handling large file uploads.

Cheers!
@Thomas I'll post a benchmark tomorrow. For typical uses, the overhead is not signifiant. However, HttpFoundation objects are still the recommended way. The PSR-7 Bridge should be used only when dealing with middlewares and libraries supporting the new standard.
nice!
That's a nice first step, I can't wait for HttpKernelInterface to rely on PSR-7 RequestServerInterface to unleash the full power of PSR middlewares (I wouldn't mind a BC break for this).
Here's the blog post from @dunglas with more details: http://dunglas.fr/2015/06/using-psr-7-in-symfony/

And a benchmark for a simple application (also included in the above post): https://blackfire.io/profiles/compare/6af13ebb-de9c-453f-9d87-681bf416eeac/graph

Cheers!
Great article! Thanks!

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.