PHP - вызов массива пользовательских функций или класс отражения, передаваемый по ссылке?
Я пытаюсь отправить запрос в рамках MVC. У меня есть объект маршрутизации, который сопоставляет текущий URI с определенными маршрутами. Если есть совпадение, он возвращает экземпляр объекта маршрута. Через этот объект маршрута я могу получить доступ к согласованному контроллеру, методу и аргументам метода.
Я могу использовать его так:
$route->getClass(); name of controller class to instantiate
$route->getMethod(); name of method to call
$route->getArgs(); array holding arguments that should be passed to method
Я также могу добавить новые аргументы, если мне нужно. Например, я могу добавить контейнер внедрения зависимостей и текущие экземпляры объектов HTTP-запроса в такие аргументы, как это:
$route->addArg('container', $container);
$route->addArg('request', $request);
Теперь $route->getArgs содержит все аргументы, извлеченные из URI, но также экземпляр $container и экземпляр $request. $container - это контейнер для инъекций зависимостей, который я написал. А $request - это объект, представляющий текущий HTTP-запрос.
Итак, идея состоит в том, чтобы создать экземпляр маршрутизатора, получить текущий маршрут, а затем добавить объекты, которые я хотел бы использовать внутри каждого контроллера методов/действий. А затем передайте этот объект маршрута диспетчеру, и когда запрос будет отправлен, я смогу использовать $контейнер, $запрос и другие аргументы в каждом контроллере метода/действия.
Проблема, с которой я сталкиваюсь, заключается в том, что когда я использую, скажем, контроллер блога и метод публикации. По умолчанию и всегда у него должен быть экземпляр $container и $request (так как я вставил их в Route::$args, плюс любой другой аргумент/переменная, определенная в определениях маршрутов или извлеченная из URI.
Поэтому, когда я в своем контроллере блога, публикую метод, я хочу, чтобы он действовал так:
public function post($container, $request)
{
if($request->isAjax) {
// -- Its ajax request
}
$twig = $container->getService("Twig");
}
Я отправляю запрос что-то вроде этого:
Я использую call_user_function_array, чтобы заставить его работать:
$app = new $controller();
call_user_function_array(array($app, $method), $args);
Теперь все это работает так, как должно, но у меня есть одна проблема. Когда я использую этот контроллер post, я должен быть осторожен, в каком порядке упорядочены аргументы метода post.
Итак, я могу сделать это:
public function post($id, $url, $container, $request) {
// -- SNIP --
}
Но я не могу использовать его таким образом:
public function post($container, $url, $request, $id) {
/-- SNIP --
}
Итак, вы поняли проблему, я не могу смешивать аргументы в своем методе так, как я хочу, и мне нужно следить за порядком, в котором эти аргументы получают определено в маршруте: массив $args.
Каждый контроллер метода/действия должен иметь $request и экземпляры $container плюс аргументы, полученные через URI или определенные в определении маршрута.
Есть ли какой-нибудь способ заставить его работать без необходимости думать, в каком порядке метод post получает аргументы? Имеет ли это какое-то отношение к передаче по ссылке? Так как php передает переменные по значению?
Я использую call_user_function_array, и я хочу найти решение для вызов_user_function_array. Возможно ли это?
Если нет, можно ли это сделать с помощью класса отражения?
2 answers
С помощью класса отражения вы можете получить имена аргументов каждого параметра функции, которую вы хотите вызвать, и таким образом очень легко проверить, находятся ли они в правильном порядке.
Вы не можете сделать это просто с помощью call_user_function_array
.
В частности, вы можете использовать getParameters() method
в классе Метод отражения.
С этого момента, я думаю, вы знаете, что делать (проверьте каждый ключ массива параметров с ключом переданного аргумента, и все готово).
Это решение моей проблемы:
Итак, у меня есть все необходимое для отправки запроса:
$class = "\\Application\\Controller\\Blog";
$method = "post";
$args = array('id' => 1, 'url' => 'some-url', 'container' => DICOBJ, 'request' => RQSTOBJ);
Теперь мне нужно отправить этот запрос, чтобы пользователь мог вставлять аргументы по своему усмотрению в любом порядке и если он хочет.
Вот что нужно сделать:
$app = new $class();
$rm = new \ReflectionMethod($app, $method);
$params = $rm->getParameters();
$argsOrdered = array();
foreach($params as $param) {
$argsOrdered[$param->getName()] = $args[$param->getName()];
}
call_user_func_array(array($app, $method), $argsOrdered);
Та-дааа!!!
Итак, что это делает, так это получает определенные пользователем аргументы и возвращает их в виде массива в порядке, в котором пользователь их написал. А затем мы создадим еще один массив $ARGSORDERED, содержащий только аргументы пользователь хочет, заказал так, как он хочет:)
Я использую метод отражения для проверки метода. И в конце вызов_user_func_array для отправки запроса, но вы также можете использовать класс отражения для получения экземпляра контроллера.
Вот и все. Находите ли вы это решение элегантным? Можно ли это сделать быстрее?