我已经开始学习Symfony2了。我遇到了一个疑问:如果我有这条路线:
# app/config/routing.yml
hello:
path: /hello/{name}
defaults: { _controller: AcmeHelloBundle:Hello:index }
这个控制器:
// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
class HelloController
{
public function indexAction($name)
{
return new Response('<html><body>Ciao '.$name.'!</body></html>');
}
}
内部Symfony2(在app / bootstrap.php.cache内)调用调用user_func_array()PHP内置函数:
$arguments = $this->resolver->getArguments($request, $controller);
$response = call_user_func_array($controller, $arguments);
对getArguments()方法的调用返回一个参数数组以传递给action方法。但如果控制器是:
// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
class HelloController
{
public function indexAction($n)
{
return new Response('<html><body>Ciao '.$n.'!</body></html>');
}
}
Symfony会抱怨RuntimeException,因为没有设置param $ n。
我的问题是:Symfony如何控制这种行为,我的意思是,如果一个路由有一个{name}参数,为什么控制器必须有一个带$ name参数的动作方法,参数必须被称为$ name?
因为在普通的PHP中,这可以工作:
$name = 'Alex';
function indexAction($n) {
echo $n;
}
$f = 'indexAction';
$arguments = array($name);
call_user_func_array($f, $arguments);
即使函数签名接受名为$ n的param而不是$ name。
我希望这个问题是可以理解的,如果没有,请告诉我,我会进行编辑。
感谢您的关注!
答案 0 :(得分:4)
所有这一切都在Controller Resolver HttpKernel/Controller/ControllerResolver.php中通过getArguments()
&amp; doArguments()
。
为了更好地理解,您可以在Getting The Controller Arguments
中找到所需内容修改:回答评论。
Symfony是否在内部使用ReflectionParameter类来跟踪方法签名的参数并将它们与路径参数匹配?
是的,ControllerResolver使用:
ReflectionMethod如果$controller
是方法,则跟踪方法签名的参数
ReflectionObject如果$controller
是对象
ReflectionFunction如果$controller
是函数
以下是:
public function getArguments(Request $request, $controller)
{
if (is_array($controller)) {
$r = new \ReflectionMethod($controller[0], $controller[1]);
} elseif (is_object($controller) && !$controller instanceof \Closure) {
$r = new \ReflectionObject($controller);
$r = $r->getMethod('__invoke');
} else {
$r = new \ReflectionFunction($controller);
}
return $this->doGetArguments($request, $controller, $r->getParameters());
}
答案 1 :(得分:1)
答案 2 :(得分:1)
在您的示例中,您的操作只有一个参数,因此我们很明显需要从路径中填充它。
要扩展您的示例,如果您向路线添加了另一个参数,例如:
# app/config/routing.yml
hello:
path: /hello/{name}/{surname}
defaults: { _controller: AcmeHelloBundle:Hello:index }
并将您的控制器更改为:
// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
class HelloController
{
public function indexAction($s, $n)
{
return new Response('<html><body>Ciao '.$n.' '.$s.'!</body></html>');
}
}
Symfony不知道填充哪个路由参数的变量$s
或$n
。
如果您改变行动:
public function indexAction($surname, $name)
{
return new Response('<html><body>Ciao '.$name.' '.$surname.'!</body></html>');
}
现在,Symfony可以查看您的参数名称并将它们映射到路由参数。这也意味着只要名称与路由参数匹配,您就可以按任何顺序拥有indexAction
个参数。我相信Symfony在内部使用Reflection API来解决所有问题。