Стандартный PHP API для работы с HTTP запросами давно устарел. Программисты научились не использовать глобальные переменные, но стандартные суперглобалы как $_GET, $_SERVER все еще напоминают нам о далеком прошлом. Конечно фреймворки инкапсулируют эту информацию в свои Request\Response классы, но таких реализаций очень много и пока еще не было единственного стандарта. Стандарт PSR-7 от PHP-FIG как раз должен привести репрезентацию HTTP протокола к единственному знаменателю что позволит писать Middleware который будет работать сразу на многих фреймворках. Он пока еще не принят, но досрочное голосование показало практически единоголосную поддержку нового стандарта. PHPixie готовясь к релизу версии 3.0 уже приняла и имплементировала PSR-7, а также предоставляет обертки для упрощенной работы с интерфейсом. Если вы хотите создать свой микрофреймворк то взяв PHPixie HTTP за основу, сможете добиться результатов уже за один вечер.
Теперь посмотрим на саму реализацию:
$slice = new \PHPixie\Slice();
$http = new \PHPixie\HTTP($slice);
Request
PSR-7 довольно упрощенный интерфейс и предоставляет параметры $_GET и $_POST в виде массивов как и сам PHP, обертки PHPixie значительно упрощают работу с ними:
//Строим запрос из глобальных переменных
$request = $http->request();
//Можно также явно предоставить уже полученную
//имплементацию PSR-7 ServerRequestInterface
$request = $http->request($serverRequest);
//$_GET
$query = $request->query();
//$_POST
$query = $request->data();
//Дополнительные аттрибуты
//Например данные из рутинга
$query = $request->attributes();
//$_GET['pixie']
$query->get('pixie');
//С дефолтным значением
$query->get('pixie', 'Trixie');
//Выбросит ошибку если параметр отсутствует
$query->getRequired('pixie');
//$_GET['user']['name'];
$query->get('user.name');
//Или так
$userData = $query->slice('user');
$userData->get('name');
//Кстати в таком случае $userData
//это экземпляр \PHPixie\Slice\Data
//никак не связанного с HTTP
//и его можно смело передать куда-то еще
//Доступ к параметрам сервера аналогичен
$request->server()->get('http_host');
//получит все значение хедера через кому
$request->headers()->get('host');
$request->headers()->getRequired('host');
//значения хедера как массив
$request->headers()->getLines('accept');
//Загруженные файлы по стандарту PSR-7
$uploadedFile = $request->uploads()->get('file');
$uploadedFile->move('/images/fairy.png');
//Информация о URI запроса
$uri = $request->uri();
$path = $uri->getPath();
//И наконец-то чтобы получить чистую
//реализацию ServerRequestInterface
$serverRequest = $request->serverRequest();
Response
Кроме самой обертки над HTTP ответами, PHPixie также сможет построить часто используемые ответы автоматически, чтобы избавить вас от возни с хедерами. Конечно после того как ответ построен его можно модифицировать по вкусу.
$responses = $http->responses();
//Самый простой ответ
$response = $responses->string('hello world');
//JSON с правильными хедерами что запрещают кэш
$responses->json(array('name' => 'Pixie'));
//Редирект
$responses->redirect('http://phpixie.com/');
//Стриминг файла
$responses->streamFile('pixie.png');
//Скачка текста как файл на компьютер пользователя
//например для CSV, TXT
$responses->download('name.txt', 'text/plain', 'Trixie');
//Скачка реального файла
$responses->downloadFile('pixie.png', 'image.png', 'images/fairy.png');
//Модификация статуса
$response->setStatus('404', 'Not Found');
//Стандартный текст ответа подставится автоматически
$response->setStatus('404');
//Модификация хедеров
$response->headers->set('Content-Type', 'text/csv');
//Получить PSR-7 ResponseInterface
$response->asResponseMessage();
//И вывести
$http->output($response);
Context
Казалось бы это все, но мы пропустили cookies и сессию. Они относятся как до запроса так и до ответа и часто к ним требуется доступ не только в контроллере, но и в других местах, например в модуле авторизации. PHPixie выделяет их в отдельный Context.
//Сначало надо получить контекст относительно запроса
$context = $http->context($request);
//А дальше все просто и по аналогии
$cookies = $context->cookies();
$session = $context->session();
$cookies->set('lang', 'en');
$session->getRequired('user_id');
//Надо только помнить указывать контекст
//при выводе ответа
$http->output($response, $context);
$response->asResponseMessage($context);
Существуют и другие имплементации PSR-7, но они пока без оберток и контекста что делает работу с ними довольно неудобной. Довольно большое число из них используют трейты и тем самым нуждаются в версии PHP 5.4+.
В то время все библиотеки PHPixie работают под любой версией PHP старше 5.3 (включая новую 7 и HHVM) и вдобавок на 100% покрыты юнит тестами. Сам код можно найти на github.com/phpixie/http
Комментарии (7)
hanovruslan
27.04.2015 10:07А разве голосование по PSR-7 не отменено? С объяснением, что нужно дорабатывать…
jigpuzzled Автор
27.04.2015 11:42Отменено, но только ради маленьких поправок. Довольно скоро будет уже полностью принят
PQR
27.04.2015 12:07В PSR-7 используются object-values, т.е. не изменяемые объекты, например $message = $message->withHeader('Location', 'http://example.com');
А у вас выглядит как мутабельный объект $response->setStatus('404'); — ваш response действительно меняется или надо переприсваивать $response = $response->setStatus('404')?jigpuzzled Автор
27.04.2015 12:38Наш меняется, но наш Response это не PSR-7 ResponseInterface. Зато он умеет превращатся в таковой:
$psrResponse = $response->asResponseMessage($context);
Конечно можно сразу по желанию построить и PSR Response:
$psrResponse = $http->messages()->response($protocolVersion, $headers, $body);
ajaxtelamonid
Поражает упорство, с каким вы, несмотря на простреленные обе ноги и гирю на шее (я про выбранное название фреймворка и общий брендинг) продолжаете ползти к цели. Молодцы.
jigpuzzled Автор
Спасибо =)
Брендинг чуть изменится когда все будет готово