What’s behind responding to requests in PHP

Have you ever wondered what’s going on underneath your framework when a client requests you to recalculate the trajectory of an asteroid heading towards Earth, or when an accountant wants to generate an annual report or when the user wants to see a list of videos with funny cats?

Image for post
Image for post

Where it all gets started?

It all takes places between these lines. In Laravel’s HTTP entry point, our good old index.php. Here’s what it does:

  • The application is started — line 1,
  • The request is handled — lines 3–5,
  • The response is sent — line 7,
  • The application is terminated — line 9.
<?php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response)​;

You might be curious what hides in lines 3 to 7.

Generally we all know the flow — we receive a request, perform some operation in our controller and return a response, right?

Today I would like to dig into the last part of the flow — returning the response. Let’s go to the controller then.

The abstraction behind the response

This is how a response usually looks like in the controller method. We often return JSONs. But what causes this data to appear in the response body? To answer this question we need to dig deeper — for the sake of this example — into SymfonyHttpFoundation.

public function controllersMethod(Request $request)
{
$bo = new BusinessObject();
$bo->doStuff($request->all());
return response()->json(['success' => true], 200);
}

The response function (line 7) is just a helper. What’s happening inside it is a call to ResponseFactory to create a proper object that implements the \Illuminate\Http\Response interface. Because we want our response to be in JSON format it’s going to create an \Illuminate\Http\JsonResponse object. That’s just the beginning, though. This class extends from Symfony\Component\HttpFoundation\JsonResponse which allows us to set data with proper encodings. JsonResponse in turn extends from Symfony\Component\HttpFoundation\Response which is finally our base class that is responsible for sending responses to clients.

So what we know for now is that we have our $response variable from the beginning of this post. As you remember, the send() method was called on this variable. This is how this method looks in Symfony\Component\HttpFoundation\Response.

public function send()
{
$this->sendHeaders();
$this->sendContent();
if (\function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
static::closeOutputBuffers(0, true);
}
return $this;
}

This one’s pretty simple. It should send headers and content of a response, then clean up. That’s all. But what does the sendContent() method contain?

The response

public function sendContent()
{
echo $this->content;
return $this;
}

It’s echo, which is probably the simplest PHP functionality (it’s not a function, though. Read the docs for more information). Its only responsibility is to print a string given as a parameter. And where is this string printed? You may remember but let me refresh your memory. Below you can see the listing from the beginning of this post. Line 7 as mentioned before is our response — it means that the string outputted from the echo will become the content of the index.php file. And that’s our response.

<?php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

What is the lesson from this post? There are several, actually:

  • Create simple methods — as simple as they might be. It’s easier to read one hundred 10-line functions than ten 100-line,
  • Cover your core code with an abstraction layer. It will make your code more reusable. As you saw in the Response example what is returned from the response() helper is interface — this makes your code more polymorphic and open to easier add of new functionalities. You will see the benefits of using polymorphism on the first change request from your client,
  • Some part of your code has to do the “dirty job” so don’t be afraid to write “echos” — they were invented to serve some purpose. But use it for the purposes which they were created for. Hide them well in the lower layers of your code. So that on a daily basis you can mainly write beautiful business objects which help to improve the world.

Originally posted on my personal blog

Written by

Developer. Enthusiast of analysis and event storming

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store