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

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

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

Начать курс

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

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

В этом руководстве мы разберём основные концепции асинхронного программирования в PHP, рассмотрим популярные библиотеки (ReactPHP, Amp), а также современные возможности языка — Fiber и генераторы.

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

В основе любого асинхронного подхода лежит Event Loop (цикл событий). Это бесконечный цикл, который проверяет, не произошло ли какое-либо событие (например, завершился HTTP-запрос или чтение файла). Если событие произошло, выполняется соответствующий обработчик. При этом основной поток не блокируется — он может переключиться на другую задачу.

Неблокирующий ввод-вывод (Non-blocking I/O) — ключевой принцип. В синхронном коде вызов file_get_contents() блокирует выполнение скрипта до полной загрузки файла. В асинхронном режиме вы инициируете операцию и продолжаете выполнять другой код, а результат приходит через callback или Promise.

Пример: синхронный vs асинхронный запрос

// Синхронный код (блокирующий)
$start = microtime(true);
$data1 = file_get_contents('http://example.com/api1');
$data2 = file_get_contents('http://example.com/api2');
echo "Время выполнения: " . (microtime(true) - $start) . " сек"; // ~2 сек (если каждый запрос по 1 сек)

// Асинхронный код (ReactPHP)
$loop = React\EventLoop\Factory::create();
$client = new React\Http\Browser($loop);

$promise1 = $client->get('http://example.com/api1');
$promise2 = $client->get('http://example.com/api2');

$promise1->then(function ($response) {
    echo "Ответ 1 получен\n";
});
$promise2->then(function ($response) {
    echo "Ответ 2 получен\n";
});

$loop->run();
// Время выполнения ~1 сек (запросы выполняются параллельно)

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

На сегодняшний день две наиболее популярные библиотеки — ReactPHP и Amp. Обе предоставляют Event Loop, Promise, а также готовые компоненты для работы с HTTP, сокетами и файловой системой.

ReactPHP

ReactPHP — это зрелая библиотека, которая существует с 2012 года. Она предоставляет низкоуровневый доступ к циклу событий и множество компонентов: react/socket, react/http, react/dns и другие.

// Пример HTTP-сервера на ReactPHP
$loop = React\EventLoop\Factory::create();
$server = new React\Http\Server($loop, function (Psr\Http\Message\ServerRequestInterface $request) {
    return new React\Http\Message\Response(
        200,
        ['Content-Type' => 'text/plain'],
        "Hello, Async World!\n"
    );
});
$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
$server->listen($socket);
echo "Сервер запущен на http://127.0.0.1:8080\n";
$loop->run();

Amp

Amp использует корутины (generator-based coroutines) и предоставляет более высокоуровневый API. Вместо цепочек then() вы используете yield и await, что делает код похожим на синхронный.

// Пример с Amp
\Amp\Loop::run(function () {
    $response = yield \Amp\Http\Client\HttpClient::request('http://example.com');
    $body = yield $response->getBody()->buffer();
    echo $body;
});

Fiber: асинхронность в ядре PHP 8.1

Начиная с PHP 8.1, в язык были добавлены Fiber — легковесные потоки выполнения, управляемые на уровне языка. Fiber позволяют приостанавливать выполнение функции и возобновлять его позже, не блокируя основной поток. Это значительно упрощает написание асинхронного кода без внешних библиотек.

Пример использования Fiber

function asyncHttpRequest($url): string {
    $fiber = new Fiber(function () use ($url) {
        // Эмуляция асинхронного запроса (замена на реальный curl или ReactPHP)
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    });
    
    $fiber->start();
    // Можно выполнять другой код, пока Fiber не завершится
    // ...
    return $fiber->resume(); // Возвращает результат
}

// Использование
$result1 = asyncHttpRequest('http://example.com/api1');
$result2 = asyncHttpRequest('http://example.com/api2');
echo "Результат 1: $result1\n";
echo "Результат 2: $result2\n";

Важно: Fiber не делают I/O автоматически неблокирующим — для этого всё равно нужны неблокирующие драйверы (например, ext-curl с опцией CURLOPT_TIMEOUT). Однако Fiber дают удобный синтаксис для организации асинхронного потока.

Promises и корутины: работа с асинхронными результатами

Promise — это объект, представляющий результат асинхронной операции, который может быть доступен сейчас, позже или никогда. В PHP Promises реализованы в ReactPHP и Amp. Они имеют три состояния: pending (ожидание), fulfilled (выполнено успешно), rejected (отклонено с ошибкой).

Цепочки Promise

$promise = $client->get('http://example.com')
    ->then(function ($response) {
        // Обработка успешного ответа
        $data = json_decode($response->getBody());
        return $data->id;
    })
    ->then(function ($id) use ($client) {
        // Второй запрос, зависящий от первого
        return $client->get("http://example.com/user/{$id}");
    })
    ->then(function ($response) {
        echo "Финальный ответ: " . $response->getBody();
    })
    ->otherwise(function ($error) {
        echo "Ошибка: " . $                

Блоги

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