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. Возможно ли это?

Если нет, можно ли это сделать с помощью класса отражения?

Author: otporan, 2012-10-19

2 answers

С помощью класса отражения вы можете получить имена аргументов каждого параметра функции, которую вы хотите вызвать, и таким образом очень легко проверить, находятся ли они в правильном порядке. Вы не можете сделать это просто с помощью call_user_function_array.

В частности, вы можете использовать getParameters() method в классе Метод отражения.

С этого момента, я думаю, вы знаете, что делать (проверьте каждый ключ массива параметров с ключом переданного аргумента, и все готово).

 1
Author: Shoe, 2012-10-19 15:18:54

Это решение моей проблемы:

Итак, у меня есть все необходимое для отправки запроса:

$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 для отправки запроса, но вы также можете использовать класс отражения для получения экземпляра контроллера.

Вот и все. Находите ли вы это решение элегантным? Можно ли это сделать быстрее?

 2
Author: otporan, 2012-10-19 21:23:39