Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/244.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php Symfony-更改控制器的实例化和执行方式_Php_Symfony - Fatal编程技术网

Php Symfony-更改控制器的实例化和执行方式

Php Symfony-更改控制器的实例化和执行方式,php,symfony,Php,Symfony,注意:从2.8版开始,Symfony为服务配置提供了autowire:true,从3.3版开始,Symfony提供了alias(而不是autowire\u类型)来将具体对象别名到接口,以便将依赖项自动注入到“控制器即服务”中。还有一个包允许控制器“动作”方法的自动接线,尽管我已经离开了这个包,并且更多地关注ADR模式的变化(基本上,这是一个带有接口方法的单个“action”类,而不是在单个类中推送一堆actions方法,最终导致架构噩梦)。这就是我多年来一直在寻找的,现在不再需要“钩住”一个像样

注意:从2.8版开始,Symfony为服务配置提供了
autowire:true
,从3.3版开始,Symfony提供了
alias
(而不是
autowire\u类型
)来将具体对象别名到接口,以便将依赖项自动注入到“控制器即服务”中。还有一个包允许控制器“动作”方法的自动接线,尽管我已经离开了这个包,并且更多地关注ADR模式的变化(基本上,这是一个带有接口方法的单个“action”类,而不是在单个类中推送一堆actions方法,最终导致架构噩梦)。这就是我多年来一直在寻找的,现在不再需要“钩住”一个像样的递归依赖注入程序(auryn)由于框架现在处理的是四年前应该有的东西,我将把这个答案留在这里,以防有人想跟踪我所做的步骤,看看内核是如何工作的,以及这个级别上的一些可用选项


注意:尽管这个问题主要针对Symfony 3,但它也应该与Symfony 2的用户相关,因为内核逻辑似乎没有太大变化

我想更改控制器在Symfony中的实例化方式。它们的实例化逻辑当前位于,更具体地说,。我想用我自己的执行该特定行的注入器替换
call\u user\u func\u array($controller,$arguments)

到目前为止,我尝试了以下几种选择:

  • 用我自己的方法扩展
    HttpKernel::handle
    ,然后由symfony调用
这样做的缺点是,因为handleRaw是私有的,我不能在没有黑客反射的情况下扩展它,所以我必须复制和粘贴一吨代码

  • 创建和注册新的控制器冲突解决程序
这是我的一个基本误解,所以我想我应该在这里记录它。解析程序的工作是解决在哪里找到作为可调用的控制器。它实际上还没有被调用。我非常高兴Symfony如何从
routes.yml
获取路由,并找出作为可调用的控制器调用的类和方法可呼叫

  • 内核上添加事件侦听器。请求
看一下,我们可以看到它有以下典型的用途:

要向请求中添加更多信息,请初始化部分系统,或在可能的情况下返回响应(例如,拒绝访问的安全层)

我认为,通过创建一个新的侦听器,使用我的自定义注入器创建我的控制器,然后在该侦听器中返回响应,将绕过实例化控制器的其余代码。这就是我想要的。!但这有一个主要缺陷:

Symfony探查器没有出现或任何类似的东西,这只是我的反应,就这样。死了。我发现我可以将优先级从31切换到33,并让它在我的代码和Symfony之间切换,我相信这是因为路由器侦听器。我觉得我走错了路

  • 收听事件
不,这允许我更改
call\u user\u func\u array()

我已经记录了我的想法,但我已经出局了。我如何才能实现以下目标

  • 更改控制器的实例化和执行方式,特别是
    call\u user\u func\u array()
  • 如果我的控制器实例化不起作用,请返回默认控制器实例化
  • 允许其他一切按预期工作,如分析器加载
  • 能够将其与其他用户的扩展捆绑在一起

我为什么要这样做

控制器可以针对不同的情况使用许多不同的方法,每个方法都应该能够针对其各自需要的内容键入提示,而不是让构造函数获取所有内容,其中一些内容甚至可能无法使用,具体取决于正在执行的控制器方法这是一个“对象边缘情况”,但它们就是这样


我想用我自己的递归自动连接注入器来替换控制器的创建方式,以及它们的执行方式,再次使用通过我的注入器的递归自省,因为默认的Symfony软件包似乎没有此功能。即使使用最新的“autowire”Symfony 2.8+中的服务选项。

为什么不从自定义
ControllerResolverInterface
返回您自己的可调用项,以您想要的方式实例化
控制器并调用它

它基本上是一个装饰师

您可以使用自己的
instanceController()
方法实现来扩展
Symfony\Component\HttpKernel\Controller\ControllerResolver
,也可以从头开始实现
ControllerResolverInterface

UPD:

当Symfony调用用户函数数组($controller,$arguments);
调用
handleRaw()
时,
$controller
变量是您从自定义的
ControllerResolver
返回的。这意味着您可以从解析程序返回任何可调用的内容(可以是
[$this,“callController”]
f.e.)在这个callable中,您可以使用Auryn创建一个新的
控制器
,并调用它

UPD2:

如果你还在为此挣扎,我将添加一个例子,因为你可能会错过我在这里的意思

use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;

class AutowiringControllerResolver extends ControllerResolver
{
    // ... constructor stuff; assume $injector is a part of this class

    protected function createController($controller)
    {
        $controller = parent::createController($controller);

        return function (...$arguments) use ($controller) {
            // you can do with resolved $arguments whatever you want
            // or you can override getArguments() method and return
            // empty array to discard getArguments() functionality completely

            return $this->injector->execute($controller);
        };
    }

    protected function instantiateController($classname)
    {
        return $this->injector->make($classname);
    }
}

控制器解析器实际上做两件事。第一件是获取控制器。第二件是获取给定操作的参数列表<
controller_resolver:
    class: AppBundle\ControllerResolver
    arguments: []
kernel.request:
    class: MyCustomRequestListener
    tags:
        - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 33 /** Important, we'll get to why in a minute **/ }
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;

class AutowiringControllerResolver extends ControllerResolver
{
    // ... constructor stuff; assume $injector is a part of this class

    protected function createController($controller)
    {
        $controller = parent::createController($controller);

        return function (...$arguments) use ($controller) {
            // you can do with resolved $arguments whatever you want
            // or you can override getArguments() method and return
            // empty array to discard getArguments() functionality completely

            return $this->injector->execute($controller);
        };
    }

    protected function instantiateController($classname)
    {
        return $this->injector->make($classname);
    }
}
$arguments = $this->resolver->getArguments($request, $controller);
$response = call_user_func_array($controller, $arguments);