Асинхронное программирование в PHP: полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в асинхронное программирование в PHP

Традиционно PHP считается синхронным языком: каждый запрос выполняется последовательно, блокируя выполнение до завершения операции ввода-вывода (например, чтения файла или запроса к базе данных). Однако с ростом популярности высоконагруженных веб-приложений и микросервисов возникла потребность в обработке десятков тысяч одновременных соединений без масштабирования количества процессов. Асинхронное программирование решает эту проблему, позволяя выполнять операции конкурентно в рамках одного потока.

В этом руководстве мы разберем, как работает асинхронность в PHP, какие инструменты доступны и как правильно строить неблокирующие приложения. Вы узнаете о генераторах, корутинах, библиотеках ReactPHP, Amp и Swoole, а также о новом расширении Fibers.

Основы асинхронности: Event Loop и неблокирующий ввод-вывод

Асинхронное программирование базируется на концепции Event Loop (цикла событий). Это бесконечный цикл, который ожидает и обрабатывает события: запросы к сети, завершение операций ввода-вывода, таймеры. Вместо того чтобы ждать завершения операции, код регистрирует колбэк (callback), который выполняется, когда данные готовы. Это позволяет не тратить процессорное время на ожидание.

PHP традиционно использует блокирующие функции (например, file_get_contents() или sleep()). Для асинхронной работы нужно заменять их неблокирующими аналогами. Вот простой пример с использованием библиотеки ReactPHP:

<?php
require 'vendor/autoload.php';

use React\EventLoop\Factory;
use React\Promise\Promise;

$loop = Factory::create();

// Асинхронное чтение файла
$promise = new Promise(function ($resolve, $reject) use ($loop) {
    $loop->addTimer(0.001, function () use ($resolve) {
        $content = file_get_contents('/etc/hosts');
        $resolve($content);
    });
});

$promise->then(function ($data) {
    echo "Прочитано: " . strlen($data) . " байт\n";
});

echo "Этот код выполнится сразу, не дожидаясь чтения файла\n";
$loop->run();
?>

В этом примере addTimer регистрирует задачу, которая будет выполнена в следующем тике цикла. Event Loop не блокируется, и мы видим сообщение сразу, а результат чтения появляется позже.

Генераторы и корутины: управление потоком выполнения

Генераторы (yield) появились в PHP 5.5 и позволяют приостанавливать выполнение функции, возвращая промежуточные значения. На их основе строятся корутины — легковесные потоки, которые могут добровольно отдавать управление. В сочетании с Event Loop генераторы позволяют писать код, который выглядит как синхронный, но выполняется асинхронно.

Рассмотрим пример с библиотекой Amp, которая использует корутины:

<?php
require 'vendor/autoload.php';

use Amp\Loop;
use Amp\Delayed;

// Асинхронная корутина
$coroutine = function () {
    echo "Начало корутины\n";
    // Приостанавливаемся на 1 секунду без блокировки
    yield new Delayed(1000);
    echo "Прошла 1 секунда\n";
    yield new Delayed(500);
    echo "Прошло еще 0.5 секунды\n";
};

Loop::run(function () use ($coroutine) {
    // Запускаем корутину
    $result = yield from $coroutine();
    echo "Корутина завершена\n";
});
?>

В этом коде yield new Delayed(1000) приостанавливает выполнение корутины, передавая управление обратно Event Loop. Через 1 секунду выполнение возобновляется с того же места. Это позволяет обрабатывать тысячи таких корутин одновременно, не создавая новые процессы.

Библиотеки и инструменты для асинхронного PHP

Для работы с асинхронностью в PHP существует несколько зрелых библиотек. Рассмотрим три наиболее популярных.

ReactPHP

ReactPHP — старейшая и наиболее известная библиотека. Она предоставляет Event Loop, Promise (аналоги JavaScript), потоки и сокеты. ReactPHP идеально подходит для:

  • Создания HTTP-серверов и клиентов
  • Работы с WebSocket
  • Параллельной обработки запросов к API

Пример асинхронного HTTP-запроса с ReactPHP:

<?php
require 'vendor/autoload.php';

use React\EventLoop\Factory;
use React\HttpClient\Client;

$loop = Factory::create();
$client = new Client($loop);

$request = $client->request('GET', 'https://api.example.com/data');
$request->on('response', function ($response) {
    $response->on('data', function ($chunk) {
        echo "Получен фрагмент: " . strlen($chunk) . " байт\n";
    });
});
$request->end();

echo "Запрос отправлен, продолжаем работу...\n";
$loop->run();
?>

Amp

Amp — более современная альтернатива, построенная на корутинах. Она предлагает более чистый синтаксис с использованием yield и Promise. Amp активно используется в проектах, требующих высокой производительности. Ключевые возможности:

  • Асинхронные потоки и сокеты
  • Параллельные операции с помощью Amp\call()
  • Таймеры и интервалы

Swoole

Swoole — это не просто библиотека, а расширение для PHP (написанное на C), которое добавляет поддержку корутин на уровне ядра. Swoole позволяет запускать PHP-приложения как постоянные процессы (а не "запуск-завершение" для каждого запроса). Он обеспечивает:

  • Встроенный HTTP-сервер
  • Корутины на уровне языка
  • Работу с TCP/UDP, WebSocket, gRPC
  • Пул соединений к БД

Пример простого сервера на Swoole:

<?php
$http = new Swoole\Http\Server("0.0.0.0", 9501);

$http->on("start", function ($server) {
    echo "Swoole HTTP сервер запущен на порту 9501\n";
});

$http->on("request", function ($request, $response) {
    // Этот код выполняется в корутине автоматически
    $response->header("Content-Type", "text/plain");
    $response->end("Hello, World!");
});

$http->                

Блоги

Рекомендаций по книгам