- PVSM.RU - https://www.pvsm.ru -
В прошлом году PHP-FIG приняла стандарт PSR-7 [1], описывающий работу с сообщениями HTTP. Хорошая статья об этом стандарте и его применении [2] была на Хабре. И хотя PSR-7 — большой шаг вперёд, ему не хватает логичного продолжения — общего интерфейса клиентов HTTP. Созданием недостающего компонента занялась группа PHP-HTTP [3].
Используя интерфейсы PSR-7 вы можете абстрагироваться от конкретной реализации запросов и ответов HTTP. Но только до тех пор, пока вам не понадобится сделать запрос самостоятельно. Тут вам придётся по-прежнему жёстко привязываться к каким-либо реализациям. При написании приложения это естественно. При написании библиотеки — совсем нехорошо. Например, наш сайт взаимодействует с пятью сторонними службами при помощи официальных и неофициальных библиотек и SDK. И каждая из них использует собственного клиента HTTP. Кто-то Guzzle, кто-то cURL, кто-то просто file_get_contents. Пять разных клиентов HTTP в одном приложении! У каждого свои особенности, свои ограничения, свои возможности настройки. Было бы здорово заменить этот зоопарк одним единственным клиентом, который использовался бы всеми компонентами приложения и библиотеками?
Основная разработка группы — набор интерфейсов Httplug [4], позволяющий библиотекам абстрагироваться от конкретного клиента HTTP, используемого в приложении. Уже есть несколько реализаций клиентов (сокеты, cURL) и адаптеров (Guzzle, React). Кроме того в рамках проекта разработано множество вспомогательных пакетов, включая пакет для Symfony.
И что же это всё даёт разработчикам?
Если вы пишете библиотеку, которая должна выполнять запросы HTTP, у вас больше нет необходимости привязываться к конкретному клиенту. Вместо этого в ''composer.json'' можно указать:
{
"require": {
"php-http/client-implementation": "^1.0"
},
"require-dev": {
"php-http/curl-client": "^1.4"
}
}
php-http/client-implementation
указывает, что вашей библиотеке требуется клиент HTTP, php-http/curl-client
— любая на выбор [5] реализация, которую можно будет использовать во время отладки и которая подтянет все необходимые для разработки интерфейсы и классы. Для отладки также может потребоваться реализация PSR-7, например guzzlehttp/psr7 [6].
Предположим, что ваша библиотека должна работать с неким API, и главный компонент — клиент этого API:
class ApiClient
{
/**
* Клиент HTTP.
*/
private $httpClient;
/**
* Фабрика запросов HTTP.
*/
private $requestFactory;
public function __construct(HttpClient $httpClient, RequestFactory $requestFactory)
{
$this->httpClient = $httpClient;
$this->requestFactory = $requestFactory;
}
Здесь:
Теперь, когда вам надо сделать запрос, можно написать что-то такое:
/**
* @param string $uri
* @param string $payload тело запроса
*/
public function apiCall($uri, $payload)
{
$request = $this->requestFactory->createRequest('POST', $uri, ['content-type' => 'foo/bar'], $payload);
$response = $this->httpClient->sendRequest($request);
// ...
}
Вот, по большому счёту, и всё, что требуется. Теперь ваша библиотека не зависит от конкретного клиента, и её пользователь сможет выбрать тот, который ему больше подходит. Посмотрим, как это делается.
Для использования описанной выше библиотеки разработчику приложения понадобится выбрать одну из реализаций [5] клиента, реализацию PSR-7 и подключить их вместе с вашей библиотекой:
$ composer require php-http/guzzle6-adapter
$ composer require ваша/библиотека
guzzle6-adapter
автоматически подтянет guzzlehttp/psr7
, поэтому отдельно его указывать необязательно.
Ещё потребуется php-http/message [11] в качестве моста к guzzlehttp/psr7
:
$ composer require php-http/message
Далее нужно создать клиента, адаптер, фабрику запросов и передать два последних в конструктор ApiClient:
use GuzzleHttpClient as GuzzleClient;
use HttpAdapterGuzzle6Client as GuzzleAdapter;
use HttpMessageMessageFactoryGuzzleMessageFactory;
$config = [
// ...
];
$guzzle = new GuzzleClient($config);
$adapter = new GuzzleAdapter($guzzle);
$apiClient = new ApiClient($adapter, new GuzzleMessageFactory);
ApiClient готов к работе. Этот же объект ($adapter) можно передать во все компоненты, которым нужен клиент HTTP.
Если в будущем возникнет надобность заменить Guzzle на что-то другое, то переписать потребуется только вот эту часть кода. Весь остальной код, работающий с HTTP, трогать не придётся.
Полностью с имеющимися пакетами и их возможностями можно ознакомиться в официальной документации [3], я же отмечу только некоторые интересные на мой взгляд.
Специальный интерфейс HttpAsyncClient [12] позволяет выполнять запросы асинхронно, используя механизм обещаний [13].
Система автообнаружения [14] на основе Puli [15] позволяет получать объекты клиента и фабрик без привязки к конкретным реализациям:
$httpClient = HttpClientDiscovery::find();
Позволяет добавлять сквозную функциональность ко всем или только некоторым клиентам HTTP. Вот некоторые примеры:
Пакет для Symfony [21], включающий поддержку нескольких клиентов, расширений и отладочной панели Symfony.
Проект находится в начале своего пути, но уже достаточно стабилен для использования в боевых условиях. Ребята ставят перед собой амбициозную цель — добиться принятия их разработок в качестве рекомендации PSR.
Автор: Mekras
Источник [22]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/146410
Ссылки в тексте:
[1] PSR-7: http://www.php-fig.org/psr/psr-7/
[2] статья об этом стандарте и его применении: http://habrahabr.ru/post/250343/
[3] PHP-HTTP: http://docs.php-http.org/en/latest/index.html
[4] Httplug: https://github.com/php-http/httplug
[5] любая на выбор: http://docs.php-http.org/en/latest/clients.html
[6] guzzlehttp/psr7: https://packagist.org/packages/guzzlehttp/psr7
[7] HttpClient: https://github.com/php-http/httplug/blob/v1.0.0/src/HttpClient.php
[8] php-http/httplug: https://packagist.org/packages/php-http/httplug
[9] RequestFactory: https://github.com/php-http/message-factory/blob/v1.0.1/src/RequestFactory.php
[10] php-http/message-factory: https://packagist.org/packages/php-http/message-factory
[11] php-http/message: https://packagist.org/packages/php-http/message
[12] HttpAsyncClient: https://github.com/php-http/httplug/blob/v1.0.0/src/HttpAsyncClient.php
[13] обещаний: http://docs.php-http.org/en/latest/components/promise.html
[14] Система автообнаружения: http://docs.php-http.org/en/latest/discovery.html
[15] Puli: http://docs.puli.io/en/latest/index.html
[16] кэширование: http://docs.php-http.org/en/latest/plugins/cache.html
[17] куки: http://docs.php-http.org/en/latest/plugins/cookie.html
[18] преобразование статусов 4xx и 5xx в исключения: http://docs.php-http.org/en/latest/plugins/error.html
[19] управление заголовками: http://docs.php-http.org/en/latest/plugins/headers.html
[20] журналирование: http://docs.php-http.org/en/latest/plugins/logger.html
[21] Пакет для Symfony: http://docs.php-http.org/en/latest/integrations/symfony-bundle.html
[22] Источник: https://habrahabr.ru/post/271687/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.