Перейти к содержимому
Теория · PHP и веб · урок 1 из 7

Как PHP обрабатывает запрос

Чему вы научитесь

Чему вы научитесь:

  • объяснять, как адрес в браузере превращается в страницу и почему PHP забывает всё после запроса;
  • читать параметры запроса из $_GET и $_POST и подставлять значения по умолчанию через ??;
  • экранировать вывод через htmlspecialchars, чтобы текст посетителя не стал кодом страницы;
  • проверять ввод через filter_var и белый список разрешённых значений.
Стойка выдачи, слева заказ GET, за стойкой колпак php, справа тарелка с листом HTML

Представьте ресторан с раздачей. Посетитель подходит к стойке и отдаёт заказ. Повар читает его, готовит блюдо по рецепту и ставит тарелку на стойку.

Следующий заказ он начинает с чистого стола и ничего не помнит о прошлом.

Сайт на PHP устроен так же:

  • браузер — посетитель;
  • веб-сервер — стойка;
  • PHP — повар;
  • ваш файл .php — рецепт.

Блюдо — это HTML, из которого браузер собирает страницу.

До сих пор вы запускали программы командой php file.php, и echo печатал в окно терминала. На сайте PHP выполняет такой же файл, только напечатанное уходит в браузер.

Запрос и ответ

Запрос — сообщение, которое браузер отправляет серверу: какой адрес открыть и, может быть, какие данные передать. Ответ — то, что сервер присылает обратно, чаще всего HTML.

Давайте разберём, что происходит, когда вы открываете адрес localhost:8000/menu.php:

  1. Браузер отправляет запрос на этот адрес.
  2. Веб-сервер — это программа, которая принимает запросы. Увидев, что имя файла заканчивается на .php, он передаёт файл в PHP.
  3. PHP выполняет menu.php с первой строки до последней, как в терминале.
  4. Всё, что программа напечатала, становится ответом.
  5. Браузер получает ответ и рисует страницу.

Встроенный сервер

Для опытов отдельный веб-сервер не нужен: он встроен в PHP. Откройте терминал в папке с файлами и выполните команду:

TEXT
php -S localhost:8000

Пока команда работает, PHP отвечает на запросы к адресу localhost:8000. Здесь localhost означает ваш компьютер, а 8000 — номер, на котором сервер ждёт запросы.

Откройте в браузере localhost:8000/menu.php, и PHP выполнит файл menu.php из этой папки. Чтобы остановить сервер, нажмите Ctrl+C в терминале.

Встроенный сервер — инструмент для разработки. Сайты в интернете работают на других веб-серверах, но путь запроса у них тот же.

HTML и <?=

Файл .php не обязан состоять из одного кода. Всё, что стоит вне тегов <?php … ?>, PHP отправляет в ответ как есть. Такой файл — HTML со вставками PHP — называют шаблоном:

PHP
<?php

$title = 'Menu';
$dish = 'Soup';
?>
<h1><?= $title ?></h1>
<p>Dish of the day: <?= $dish ?></p>

Давайте разберём по строкам:

  1. Между <?php и ?> стоит обычный код: две переменные.
  2. Вне тегов <?php … ?> идёт HTML, и PHP копирует его в ответ без изменений.
  3. <?= $title ?> — короткая запись для <?php echo $title; ?>: она печатает значение прямо посреди HTML.

Браузер получит такой ответ:

TEXT
<h1>Menu</h1>
<p>Dish of the day: Soup</p>

Закрывающий тег ?> в файле, где есть только код, не ставят. В шаблоне он нужен: после него снова начинается HTML.

Каждый запрос с чистого листа

Вот программа, которая будто бы считает посещения:

PHP
<?php

$visits = 0;
$visits++;
echo 'Visits: ', $visits, "\n"; // Visits: 1

Сколько бы раз вы ни обновили страницу, она покажет Visits: 1. На каждый запрос PHP выполняет файл заново, с первой строки, а в конце запроса уничтожает все его переменные и объекты. Следующий запрос о них ничего не знает.

Такую модель называют shared-nothing — «ничего общего»: у запросов нет общих переменных и объектов. Даже статическое свойство класса, общее для всех объектов, живёт только до конца запроса.

На настоящем сервере PHP обычно работает через php-fpm. php-fpm заранее запускает несколько копий PHP — рабочих процессов, и каждый из них обслуживает запросы по очереди. Процесс живёт долго, но после каждого запроса PHP освобождает всю память этого запроса.

Здесь картинка с поваром упрощает. У сайта тоже есть память о посетителях, только хранится она не в PHP.

Данные, которые должны пережить запрос, записывают в базу данных. А то, что нужно помнить о конкретном посетителе, хранят в сессии. Браузер приносит с каждым запросом номерок, как из гардероба, и по нему сервер находит данные посетителя.

На собеседовании часто спрашивают, переживёт ли статическое свойство следующий запрос. Ответ — нет, и это защищает запросы друг от друга: ошибка в одном не испортит данные другого.

Частая ошибка

Счётчик посещений хранят в статическом свойстве и ждут, что он будет расти:

PHP
<?php

class Counter
{
    public static int $hits = 0;
}

Counter::$hits++; // ✗
echo 'Hits: ', Counter::$hits, "\n";

Каждый запрос печатает Hits: 1, и PHP не выдаёт никаких сообщений. К концу запроса свойство исчезает вместе со всем остальным, и следующий запрос снова начинает с 0. Счётчик, который должен расти, хранят в базе данных.

Главное

  • Браузер отправляет запрос, веб-сервер передаёт файл .php в PHP, а всё напечатанное становится ответом.
  • php -S localhost:8000 запускает встроенный сервер для разработки, а <?= $x ?> печатает значение посреди HTML.
  • Каждый запрос начинается с чистого листа: в конце запроса PHP уничтожает все переменные, объекты и статические свойства.
  • То, что должно пережить запрос, хранят в базе данных или в сессии.