> Напишите функцию, которая асинхронно сделает fetch-запрос, распарсит ответ и вернет имя пользователя (PHP)

Уровень: senior · Роль: backend · Язык: PHP · Категория: Технические вопросы

Компании: витринатв

Стек: PHP

> Пример ответа

Короткий ответ

В PHP асинхронный fetch-запрос выполняется через curl_multi или библиотеки вроде Guzzle с promise-подходом. Для простого сценария достаточно синхронного file_get_contents или curl, но если требуется именно асинхронность - используем curl_multi_init или ReactPHP. Парсинг ответа - через json_decode. Функция возвращает Promise или результат после ожидания, в зависимости от выбранного подхода.

Подробное объяснение

PHP - синхронный язык по умолчанию, поэтому "асинхронный fetch" реализуется через:

  • curl_multi_* - параллельные запросы без блокировки основного потока, но с ручным управлением.
  • Guzzle с async() - возвращает promise, который можно резолвить через wait() или then().
  • ReactPHP / Amp - полноценный event loop, но это уже тяжелая зависимость.

Для задачи "сделать запрос, распарсить, вернуть имя" асинхронность оправдана только если таких запросов несколько. В противном случае синхронный curl проще и предсказуемее. В ответе на собеседовании важно показать понимание trade-off: асинхронность в PHP - это не про производительность одного запроса, а про конкурентность множества.

На практике

Для senior-позиции ожидается, что кандидат:

  • объяснит, почему в PHP нет нативного fetch как в JS;
  • предложит решение через curl_multi или Guzzle;
  • обработает ошибки сети, HTTP-статусы, некорректный JSON;
  • покажет, как вернуть результат из асинхронной функции (callback, promise, генератор).

Если задача звучит как "напишите функцию", то в контексте PHP чаще всего подразумевают синхронную обертку с curl, потому что асинхронность без event loop не даёт выигрыша. Уточните у интервьюера, что именно он хочет: конкурентность или просто "не блокировать" - это разные вещи.

Пример кода

PHP
<?php
/**
* Асинхронный fetch через curl_multi.
* Возвращает имя пользователя из JSON-ответа.
*/
function fetchUserNameAsync(string $url): string
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$mh = curl_multi_init();
curl_multi_add_handle($mh, $ch);
do {
$status = curl_multi_exec($mh, $active);
if ($active) {
curl_multi_select($mh);
}
} while ($active && $status === CURLM_OK);
$response = curl_multi_getcontent($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_multi_remove_handle($mh, $ch);
curl_multi_close($mh);
if ($httpCode !== 200) {
throw new RuntimeException("HTTP error: $httpCode");
}
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('Invalid JSON');
}
return $data['name'] ?? throw new RuntimeException('Name not found');
}
// Использование:
$name = fetchUserNameAsync('https://api.example.com/user/1');
echo $name;

Альтернатива через Guzzle:

PHP
use GuzzleHttp\Client;
function fetchUserNameAsyncGuzzle(string $url): string
{
$client = new Client();
$promise = $client->getAsync($url)->then(
function ($response) {
$data = json_decode($response->getBody(), true);
return $data['name'] ?? throw new RuntimeException('Name not found');
}
);
return $promise->wait();
}

Как отвечать на собеседовании

Начните с уточнения: "Вы имеете в виду конкурентный запрос или просто неблокирующий?" Это покажет, что вы понимаете разницу. Затем опишите два подхода: curl_multi для параллельных запросов и Guzzle для promise-стиля. Обязательно упомяните, что в PHP нет встроенного event loop, поэтому "асинхронность" - это либо ручное управление, либо внешняя библиотека. Если интервьюер ждёт простую функцию - предложите синхронный вариант и объясните, почему он достаточен.

Что проверяет интервьюер

  • Понимание модели выполнения PHP (блокирующий I/O, отсутствие нативного async/await).
  • Умение работать с curl_multi или promise-библиотеками.
  • Обработку ошибок: HTTP-статусы, таймауты, некорректный JSON.
  • Умение объяснить trade-off между синхронным и асинхронным подходом.
  • Способность выбрать правильный инструмент под задачу, а не просто "сделать асинхронно ради асинхронности".

Типичные ошибки

  • Использование file_get_contents с stream_context и попытка выдать это за асинхронность - это блокирующий вызов.
  • Игнорирование HTTP-статусов и проверки json_decode.
  • Возврат null вместо выбрасывания исключения при ошибке.
  • Утверждение, что curl_multi делает запросы "в фоне" - на самом деле он просто переключается между дескрипторами в одном потоке.
  • Забывают закрыть curl_multi - утечка ресурсов.
  • Предложение ReactPHP без объяснения, зачем это нужно в простой задаче.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью