drtoaamk20278
2014-11-27 06:50
浏览 52
已采纳

Symfony2如何将URI的参数传递给控制器​​Action方法?

I have started learning Symfony2. I came across a doubt: if I have this route:

# app/config/routing.yml
hello:
    path:      /hello/{name}
    defaults:  { _controller: AcmeHelloBundle:Hello:index }

And this controller:

// 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>');
    }
}

Internally Symfony2 (inside app/bootstrap.php.cache) calls the call user_func_array() PHP built-in function:

$arguments = $this->resolver->getArguments($request, $controller);
$response = call_user_func_array($controller, $arguments);

And the call to the getArguments() method returns an array of arguments to pass to the action method. But if the controller were:

// 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 would have complained with a RuntimeException because no param $n is set.

My question is: how Symfony controls this behaviour, I mean, if a route has a {name} param, why the controller must have an action method with a $name parameter and the parameter must be called $name?

Cause in plain PHP, this would work:

$name = 'Alex';
function indexAction($n) {
   echo $n;
}
$f = 'indexAction';
$arguments = array($name);
call_user_func_array($f, $arguments);

Even if the functions signature accepts a param named as $n and not as $name.

I hope that this question is understandable, if not, please tell me and I will make an edit.

Thanks for the attention!

图片转代码服务由CSDN问答提供 功能建议

我已经开始学习Symfony2了。 我遇到了一个疑问:如果我有这条路线:

  #app / config / routing.yml 
hello:
 path:/ hello / {name} 
 defaults  :{_ control:AcmeHelloBundle:Hello:index} 
   
 
 

此控制器:

  // src / Acme  /HelloBundle/Controller/HelloController.php
namespace Acme \ HelloBundle \ Controller; 
use Symfony \ Component \ HttpFoundation \ Response; 
class HelloController 
 {
 public function indexAction($ name)
 {
 
 
返回新的响应(  '&lt; html&gt;&lt; body&gt; Ciao'。$ name。'!&lt; / body&gt;&lt; / html&gt;'); 
} 
} 
   
 
  

内部Symfony2(在app / bootstrap.php.cache内)调用调用user_func_array()PHP内置函数:

  $ arguments = $ this-&gt; resolver  - &gt; 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 
 {
公共函数indexAction($ n)
 {
 
 
返回新的响应('&lt; html&gt;&lt; body&gt; Ciao'。$ n。'!&lt; / body&gt;&lt; /  html&gt;'); 
} 
} 
   
 
 

Symfony会抱怨RuntimeException,因为没有设置param $ n。

我的问题是:Symfony如何控制这种行为,我的意思是,如果一个路由有一个{name}参数,为什么控制器必须有一个带有$ name参数的动作方法和参数 必须称为$ name?

因为在普通的PHP中,这可以工作:

  $ name ='Alex'; 
function indexAction($ n){\  n echo $ n; 
} 
 $ f ='indexAction'; 
 $ arguments = array($ name); 
call_user_func_array($ f,$ arguments); 
   
  
 

即使函数签名接受一个名为$ n而不是$ name的参数。

我希望这个问题是可以理解的,如果没有,请告诉我和我 将进行编辑。

感谢您的关注!

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • doumengbai2031 2014-11-27 08:15
    已采纳

    It's all done in the Controller Resolver HttpKernel/Controller/ControllerResolver.php via getArguments() & doArguments().

    For a better understanding, you will find what you need in Getting The Controller Arguments


    Edit: Answer comment.

    Does Symfony use the ReflectionParameter class internally in order to keep track of the params of the method's signature and match them with the route params?

    Yes, the ControllerResolver uses:

    Here is how:

     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());
        }
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • duanke9540 2014-11-27 07:43
    1. The request is handled by the Symfony front controller (e.g. app.php);
    2. The Symfony core (i.e. Kernel) asks the router to inspect the request;
    3. The router matches the incoming URL to a specific route and returns information about the route, including the controller that should be executed;
    4. The Symfony Kernel executes the controller, which ultimately returns a Response object.

    enter image description here

    Resource

    评论
    解决 无用
    打赏 举报
  • dongshetao1814 2014-11-27 07:58

    In your example you only have one parameter on your action, so it's obvious to us that it needs to be populated from the route.

    To extend your example, if you added another parameter to the route such as:

    # app/config/routing.yml
    hello:
        path:      /hello/{name}/{surname}
        defaults:  { _controller: AcmeHelloBundle:Hello:index }
    

    And changed your controller to:

    // 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 wouldn't know which variable $s or $n to populate with which route parameter.

    If you change your action:

        public function indexAction($surname, $name)
        {
            return new Response('<html><body>Ciao '.$name.' '.$surname.'!</body></html>');
        }
    

    Now, Symfony can look at your argument names and map them to the route parameters. It also means you can have your indexAction arguments in any order as long as their names match the route parameters. I believe Symfony internally uses the Reflection API to figure all this out.

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题