Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/252.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 MVC和依赖注入,强制使用单例控制器?_Php_Model View Controller_Dependency Injection_Singleton_Inversion Of Control - Fatal编程技术网

Php MVC和依赖注入,强制使用单例控制器?

Php MVC和依赖注入,强制使用单例控制器?,php,model-view-controller,dependency-injection,singleton,inversion-of-control,Php,Model View Controller,Dependency Injection,Singleton,Inversion Of Control,我正在构建一个PHP框架,它根据MVC原则运行,并利用依赖注入。我想我把前控制器的部分拆了;有一个工作路由器,它实例化一个控制器实例,并根据请求的URI调用适当的操作 接下来是依赖注入。我想实现一个使用反射解析依赖关系的容器。这样做,我想我的控制器遇到了问题 有许多我称之为“系统依赖项”的东西需要可用于派生控制器类。实际上,我还没有创建所有这些依赖项,但控制器可以访问InputProvider(封装get/post参数或命令行参数)之类的服务,也可以访问输出依赖项,这似乎是明智的。 理想情况下,

我正在构建一个PHP框架,它根据MVC原则运行,并利用依赖注入。我想我把前控制器的部分拆了;有一个工作路由器,它实例化一个控制器实例,并根据请求的URI调用适当的操作

接下来是依赖注入。我想实现一个使用反射解析依赖关系的容器。这样做,我想我的控制器遇到了问题

有许多我称之为“系统依赖项”的东西需要可用于派生控制器类。实际上,我还没有创建所有这些依赖项,但控制器可以访问InputProvider(封装get/post参数或命令行参数)之类的服务,也可以访问输出依赖项,这似乎是明智的。 理想情况下,我会使用框架的容器将这些依赖项注入控制器的构造函数中,但这就是我遇到问题的地方

如果我对控制器中的系统依赖项使用构造函数注入,那么如果派生控制器实现了自己的构造函数,那么我将强制它们管理基础控制器的依赖项。这似乎不是最方便用户的。 另一个选项是对系统依赖项使用setter注入,但是如果派生控制器在其构造函数中需要这些系统依赖项,则它们将无权访问这些系统依赖项

我看到的唯一一个能兼顾这两个方面的解决方案是使我的控制器成为单例。它们有一个私有构造函数,这样我就可以安全地使用setter注入,而不用担心派生类的构造函数。相反,将有一个可重写的initialize()方法(假设我以某种方式让方法注入工作),它基本上实现了构造函数的角色(例如,派生控制器的初始值设定项)。这样,initialize()方法中的构造函数注入就被方法注入所取代,在该方法中,所有系统依赖项都可用,而不需要派生控制器来管理它们

但是,一个快速的谷歌搜索似乎一致认为单例控制器是不好的做法。我很不确定如何进行。我可能对这一点设计过度,但除了希望我的应用程序能够经得起未来的考验并可维护外,我还将其视为应用最佳实践的一个小练习,因此我希望“正确”地完成工作。
我认为在这种情况下,最好的做法是将管理所需系统依赖性的责任传递给派生控制器。可能只有当派生控制器实际需要依赖项时,才应该实例化该依赖项。如果派生控制器可能永远不会使用InputProvider,那么为什么要在基本控制器中注入InputProvider呢?但与此同时,我不断回到对用户友好的话题,以及总是有一个
$this->input
成员可用是多么美好的事情,比如在CodeIgniter这样的框架中

我非常感谢所有对我的难题的贡献。我也为文字墙道歉,但我想不出任何代码示例可以让解释工作变得更容易,因为现在对我来说这一切都太抽象了

真诚地说,

严重撕裂的个体

有几种可能的解决方案:

  • 禁止控制器使用
    \u construct()
    :将其设为private-public-final,并使控制器覆盖类似
    init()
    的内容,并从构造函数调用它。然后构造函数将注入所有依赖项(反射?其他东西?),以便它们在
    init()
    中都准备好了

  • 您可以使用一个现有的DI库,比如(免责声明:我正在处理这个问题),它允许您定义依赖项,但可以在构造函数中使用它们(神奇的是,是的)

诸如此类:

<?php
use DI\Annotations\Inject;

class FooController {
    /**
     * @Inject
     * @var Bar
     */
    private $bar;

    public function __construct() {
        // The dependency is already injected
        $this->bar->sayHello();
    }

    public function setBar(Bar $bar) {
        return $this->bar = $bar;
    }
}

谢谢,这让我又回到了正轨!我倾向于使用第一种解决方案,因为我真的希望自己有编写DI代码的经验,但您让我非常好奇:在没有显式构造函数注入的情况下,您是如何使依赖项在构造函数中可用的?注意:我必须在我的基本控制器中使用
public final\uuu construct(){}
,否则子控制器根本无法实例化。@rogierpinink
public final
是!很抱歉给您带来困惑,我想到了单例模式:/。至于“构造函数注入之前”,请检查以下内容:。PHP>5.4的ReflectionClass::newInstanceWithoutConstructor()和PHP 5.3的已知序列化技巧。