#php #routing #mezzio #psr-7
#php #маршруты #mezzio #psr-7
Вопрос:
Я добавляю функциональность к этому пользовательскому маршрутизатору и пользовательскому классу запросов, чтобы иметь возможность обслуживать страницы и ответы json.
Я застрял в части маршрутизатора, где у маршрута есть параметр в URL, подобный:
example.com/apply /{переменная}
Это классы:
Класс маршрутизатора:
<?php
class Router
{
private $request;
private $supportedHttpMethods = array("GET", "POST");
function __construct(RequestInterface $request)
{
$this->request = $request;
}
function __call($name, $args)
{
list($route, $method) = $args;
if (!in_array(strtoupper($name), $this->supportedHttpMethods)) {
$this->invalidMethodHandler();
}
$this->{strtolower($name)}[$this->formatRoute($route)] = $method;
}
/**
* Removes trailing forward slashes from the right of the route.
*
* @param route (string)
*/
private function formatRoute($route)
{
$result = rtrim($route, '/');
if ($result === '') {
return '/';
}
return $result;
}
private function invalidMethodHandler()
{
header("{$this->request->serverProtocol} 405 Method Not Allowed");
}
private function defaultRequestHandler()
{
header("{$this->request->serverProtocol} 404 Not Found");
}
/**
* Resolves a route
*/
function resolve()
{
$methodDictionary = $this->{strtolower($this->request->requestMethod)};
$formatedRoute = $this->formatRoute($this->request->requestUri);
$method = $methodDictionary[$formatedRoute];
if (is_null($method)) {
$this->defaultRequestHandler();
return;
}
echo call_user_func_array($method, array(
$this->request
));
}
function __destruct()
{
$this->resolve();
}
}
Класс запроса:
<?php
include_once 'RequestInterface.php';
class Request implements RequestInterface
{
private $params = [];
public function __construct()
{
$this->bootstrapSelf();
}
private function bootstrapSelf()
{
foreach ($_SERVER as $key => $value) {
$this->{$this->toCamelCase($key)} = $value;
}
}
private function toCamelCase($string)
{
$result = strtolower($string);
preg_match_all('/_[a-z]/', $result, $matches);
foreach ($matches[0] as $match) {
$c = str_replace('_', '', strtoupper($match));
$result = str_replace($match, $c, $result);
}
return $result;
}
public function isPost()
{
return $this->requestMethod === "POST";
}
/**
* Implemented method
*/
public function getParams()
{
if ($this->requestMethod === "GET") {
$params = [];
foreach ($_GET as $key => $value) {
$params[$key] = filter_input(INPUT_POST, $key, FILTER_SANITIZE_SPECIAL_CHARS);
}
$this->params = array_merge($this->params, $params);
}
if ($this->requestMethod == "POST") {
$params = [];
foreach ($_POST as $key => $value) {
$params[$key] = filter_input(INPUT_POST, $key, FILTER_SANITIZE_SPECIAL_CHARS);
}
$this->params = array_merge($this->params, $params);
}
return $this->params;
}
}
Вот как я бы назвал маршрутизатор:
$router->get('/apply/{code}', function($request) use($myClass) {});
Какой подход был бы лучше? Я не знаю, как это решить.
Ответ №1:
Я бы настоятельно рекомендовал ознакомиться с существующими реализациями http factory, прежде чем изобретать велосипед с нуля. Даже если пользовательские реализации могут выглядеть так, как будто они обеспечивают некоторую гибкость и преимущества в краткосрочной перспективе, вы можете легко добиться успеха в среднесрочной / долгосрочной перспективе, создав приложение на основе такого подхода.
Как сам язык, так и экосистема PHP сильно эволюционируют, мы находимся в 2019 году, у нас есть десятки хорошо написанных, повторно используемых библиотек. Просто выберите свое оружие и сосредоточьтесь на своей реальной цели. Любому коду без тестов, включающему магию, не хватает composer, надлежащего механизма автоматической загрузки, хорошо написанного маршрутизатора или быстрого движка шаблонов; в большинстве случаев это причинит больше боли, чем пользы, которую он предоставляет. Мы должны прекратить повторяться.
Насколько я понимаю, ваша цель — обслуживать содержимое JSON по определенному пути URI, но вы пытаетесь изобрести маршрутизатор. Если ваша цель — написать правильный маршрутизатор, это не имеет ничего общего с интерфейсами запроса / ответа, которые упоминались в вопросе. Я бы рекомендовал сначала ознакомиться с реализациями некоторых повторно используемых, независимых от платформы маршрутизаторов, таких как FastRoute, Zend Router, Aura Router и т.д., Чтобы иметь представление. Внедрение надлежащего маршрутизатора, конечно, не является ракетостроением, но это не так просто, как вы, возможно, поняли. Тем не менее, попытка написать этот компонент также может быть образовательной, и если ваша цель в этом, дерзайте.
Вот пара советов (и новые проблемы, о которых стоит подумать):
- Существует стандарт обработчика запросов PSR-15. Отправка заголовков в частных методах с именем RequestHandler может оказаться не очень хорошей идеей.
- Обработчики запросов и маршрутизаторы — это разные компоненты, для которых требуются разные рабочие процессы. Вы смешиваете их в своем коде, и это предупреждающий знак.
- Любой связанный с этим код
__magic
создает ловушку для вас самих и для потенциальных будущих разработчиков. - Я не уверен в результате
include_once 'RequestInterface'
строки, но у нас есть интерфейсы сообщений HTTP. Я бы рассмотрел возможностьuse PsrHttpMessageServerRequestInterface
импорта в любой тип пользовательской реализации при работе с запросами. - Эхо в
__destruct
также интересно. Что вам здесь нужно, так это эмиттер. Несколько примеров: Http-отправитель, Zend Http Runner - И вот высокоуровневый ответ на ваш актуальный вопрос: вам нужно реализовать механизм (возможно, с использованием регулярных выражений) для отслеживания шаблонов в частях URI и анализа и обнаружения необязательных или обязательных именованных частей в «путях».
Лично я бы рекомендовал заглянуть в Zend Expressive. Это очень помогает разработчикам при написании легких приложений, управляемых промежуточным программным обеспечением. Лучшая особенность Expressive в том, что вы можете выбрать любое оружие в соответствии с вашими потребностями. Это не полноценный фреймворк MVC, предоставляющий новый способ написания веб-приложений, и это чертовски быстро. Вы можете свободно выбирать любой компонент, который вы хотите, например; Twig для нужд рендеринга, Symfony Console для CLI, Zend Service Manager в качестве контейнера для внедрения зависимостей, Aura Router для маршрутизации и т.д..
Вы можете попробовать это, используя всего несколько команд (при условии, что у вас глобально установлен composer):
composer create-project zendframework/zend-expressive-skeleton my-app
cd my-app
composer run --timeout=0 serve
И откройте свой браузер: http://localhost:8080
Удачи!
Комментарии:
1. спасибо за это отличное объяснение!! Это просто для учебных целей! Наконец, я использовал пакет SimpleRouter. Я заглянул в Zend expressive. Выглядит действительно красиво, я обязательно использую в следующий раз. С уважением!