От callback hell до Fibers: как изменилась асинхронность в PHP за 5 лет и почему теперь это стоит использовать

От callback hell до Fibers: как изменилась асинхронность в PHP за 5 лет и почему теперь это стоит использовать

"На PHP нельзя делать асинхронно..."

Привет, коллеги!

Если вы слышали эту фразу 5 лет назад — вам не показалось. Тогда асинхронное программирование на PHP было уделом энтузиастов, готовых мириться с:

  • Promise hell из 10+ вложенных callback'ов
  • Утечками памяти в долгоживущих процессах
  • Отсутствием асинхронных драйверов для БД
  • Блокировками event loop одним неосторожным вызовом

За последние 5 лет в PHP произошла тихая революция. Сегодня мы можем делать real-time приложения, обрабатывать десятки тысяч одновременных подключений и эффективно работать с I/O — и всё на родном PHP. Хотя если заглянуть под капот, станет ясно: это не финал, а всего лишь фундамент для гораздо более масштабных изменений.

Тогда и сейчас: эволюция технологий

2019: «Три кита» асинхронности

ReactPHP — Promise-based подход, но с callback hell:

$httpClient->get($url1)->then(function($response1) { return $httpClient->get($url2)->then(function($response2) { // И так 10 уровней вглубь... }); });

AmPHP — корутины на генераторах, но с неочевидным синтаксисом:

function fetchData(): Generator { $data = yield $httpClient->get($url); // Магия yield return process($data); }

Swoole — мощное C-расширение, но требующее пересборки PHP и с сложной отладкой.

Сейчас: Эра Fibers

PHP 8.1+ Fibers изменили всё:

$fiber = new Fiber(function() { $data1 = $httpClient->get($url1); // Приостанавливается, но не блокирует $data2 = $httpClient->get($url2); return process($data1, $data2); });

Теперь код выглядит как синхронный, но работает как асинхронный.

Решённые проблемы: что изменилось кардинально

Было: «Callback hell делает код нечитаемым»

getUser($id, function($user) { getOrders($user, function($orders) { getProducts($orders, function($products) { // Уже забыл, что было в начале... }); }); });

Стало: Линейный код с Fibers

$user = $httpClient->get("/users/{$id}"); $orders = $httpClient->get("/users/{$id}/orders"); $products = $httpClient->get("/products?ids=" . implode(',', $orderIds));

Было: «Нет асинхронных драйверов для БД»

Раньше один SELECT * FROM large_table мог заблокировать весь event loop.

Стало: Богатая экосистема

  • MySQL: amphp/mysql, swoole/coroutine-mysql
  • PostgreSQL: amphp/postgres, revolt/database
  • Redis: clue/redis-react, swoole/redis
  • HTTP: amphp/http-client, react/http

Было: «Утечки памяти в долгоживущих процессах»

После недели работы приложение «съедало» всю память сервера.

Стало: Стабильные production-решения

  • Улучшенный garbage collector в PHP 8+
  • Инструменты мониторинга: Blackfire, Tideways
  • Process managers: RoadRunner, FrankenPHP

Производительность: цифры говорят сами за себя

Традиционный PHP-FPM:

  • 1000 concurrent users = 1000 процессов PHP-FPM
  • High memory usage, slow context switching

Современный асинхронный PHP:

  • 1000 concurrent users = 1 процесс + легковесные Fibers
  • В 5-10 раз меньше потребление памяти
  • Поддержка десятков тысяч одновременных подключений

Real-кейсы: где это работает

Чат-сервер на Swoole

$server = new Swoole\WebSocket\Server('0.0.0.0', 9501); $server->on('message', function($server, $frame) { // 10,000+ одновременных подключений foreach ($server->connections as $fd) { $server->push($fd, $frame->data); } });

Парсинг данных с AmPHP

Loop::run(function() { $promises = []; // Параллельные HTTP-запросы for ($i = 0; $i < 100; $i++) { $promises[] = $httpClient->get("https://api.example.com/data/$i"); } $results = yield $promises; // Все выполняется параллельно });

Что же выбрать сегодня?

- Swoole — для максимальной производительности, real-time приложений

- AmPHP — для современного подхода с Fibers, чистый PHP

- ReactPHP — для миграции legacy-кода, постепенного перехода

- FrankenPHP — для автоматической асинхронности без переписывания кода

Но важно понимать: даже сегодня асинхронность в PHP — не silver bullet. Fibers решили проблему "как", но не "что" — нам всё ещё не хватает единых стандартов и зрелой экосистемы, как в Node.js или Go. Асинхронность в PHP всё ещё требует глубокого понимания, а не просто подключения волшебной библиотеки.

А вы используете данное в своих проектах? Делитесь опытом в комментариях!

3
Начать дискуссию