在哪里加载控制器依赖类?

时间:2014-07-19 15:00:08

标签: php dependency-injection controller

我用PHP创建了自己的原始MVC框架,我想知道在哪里加载/实例化相应的控制器依赖项?

在每个控制器的构造函数中(紧密耦合)或注入它们(松散耦合)?

我不太确定后者的唯一部分是在注入之前,在MVC范例之外的引导程序级别实例化依赖项。并非每个控制器都使用完全相同的依赖项,而不是默认的父项。我必须将它们全部实例化,这也会产生很多开销。

我已经看到一些现有的框架在构造函数中像$this->load->model('model'); // CodeIgniter那样做了,但我不知道为什么他们这样做。

5 个答案:

答案 0 :(得分:3)

我建议您注入依赖项,因此您的控制器与您的框架耦合较少。这将更容易切换到另一个框架。

关于实例化依赖项:我建议您使用(或实现)dependency injection容器。此容器应包含可以实例化服务的factories

在理想情况下,您的控制器也是服务(意味着它们在依赖注入容器中也有工厂)。

这样只会实例化特定请求所需的控制器,因此只会实例化其依赖关系。
构建自己的框架时,这意味着在路由阶段(当已知正确的控制器)之后,框架应该从容器中获取该控制器。容器本身将确保提供所需的所有依赖项。

有关简单依赖项注入容器的示例,请查看Pimple

PS:来自CodeIgniter的那一行看起来很像service locator pattern。此模式类似于dependency injection,但未提供完整 inversion of control

答案 1 :(得分:1)

问:我应该在哪里加载/实例化相应的控制器依赖项?

有多种方法。 负载和实例化概念基本上是"之前/之外"和"之后/之内"。

前后表示在加载控制器之前加载包含类(要实例化并传递给控制器​​)​​的文件。 但在加载控制器之前,您怎么知道控制器需要什么?呃..

  • 依赖关系描述文件

描述文件起作用,描述控制器与其依赖关系之间的连线。换句话说,您可以通过查看控制器的依赖关系描述文件来查看控制器的依赖关系。这个概念通常由依赖注入工具使用,它分析对象并自动拉出依赖项名称。也可以手动维护这样的布线配置文件。但这很乏味。

  • 服务定位器

Service Locator是依赖项的实例化助手。 基本上,它包含相同的信息,如依赖描述文件,但这次是registry的形式。应用程序各部分之间的链接将成为此注册表。

这两种策略都会引入开销。这是一种权衡。当您更改透视图并查看具有500多个类的应用程序中的内容时,您会发现依赖注入工具有时是值得的。

  • 手动注射

通过构造函数注入。

内部和内部表示您加载包含控制器的文件,然后开始关心依赖项。

此时该类尚未实例化,但是自动加载器可能会在场景后面做出肮脏的行为。他评估控制器文件顶部的use语句。 use语句声明了命名空间类,自动加载器解析为实现文件并加载它们。然后,您可以开始在控制器中将这些类用作依赖项。 这可能是解决问题的最简单方法,我强烈建议您查看使用命名空间和use-statements自动加载的主题。

实例化类时,您有以下可能性: use可能使用Setter Injection或Reference Injection来设置对象的依赖项。这要求您的构造函数依赖项已经解决或您的构造函数为空。 可以将这些策略结合起来。

问:这有什么作用$this->load->model('model'); // CodeIgniter

CodeIgniter是一个遗留应用程序框架。它是在命名空间自动加载不可用的时候创建的。 $this->load是一个基本的类加载助手。这与" auto"加载器相反(惊喜,惊喜)自动加载。

CodeIgniters加载器类用于加载各种其他类,例如来自视图,帮助程序,模型或用户定义的东西的库或文件。这又是一个注册表的概念。这里注册表只知道应用程序布局中的内容并解决它们。所以$this->load->model('model');意味着model函数必须有一些信息,关于模型文件在应用程序中的位置。 您提供了模型名称,文件的路径由model构成。 这很简单(除了一点开销):https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Loader.php#L223

答案 2 :(得分:0)

由于我是Symfony开发人员,我只能给你一个Symfony的参考。 我认为你应该像他们在Symfony一样,通过考虑你需要的东西来做 控制器对象。

至少,你需要:

  • 请求对象

  • 和一个模型加载器对象,为您提供所需的每个模型。

创建一个实现这几个函数的BaseController,然后使用自定义控制器扩展它。 您还可以查看Silex:http://silex.sensiolabs.org/一个Micro Framework

希望它有所帮助。

答案 3 :(得分:0)

你什么时候说"在构造函数"你的意思是传入 conatiner 并从它们中拉出依赖项(在构造函数中)?

<?php

class SomeController
{
  public function __construct($container)
  {
    $this->service1 = $contanier->get('service1);
  }
  //...
}

我建议反对,虽然更简单,更容易将控制器耦合到容器,因此使用ServiceLocator而不是真正的控制反转。

如果您希望控制器易于单元测试,则应使用控制反转:

class SomeController
{
  public function __construct($service1)
  {
    $this->service1 = $service1;
  }
  //...
}

您甚至可以将控制器创建为容器内的服务:

// this uses Pimple notation, I hope you get the point
$container['controller'] = function($c) {
  return SomeController($c['service1']);
}

使用代理服务延迟加载

此外,如果您的控制器需要的服务不仅仅是某些服务,并且您不能使用所有这些服务,您可以:

1)使用代理服务以便仅在真正需要时延迟加载服务

<?php

class ProxyService
{
  /**
   * @var Service1Type
   */
  private $actualService;

  public function __construct()
  {
    $this->actualService = null;
  }

  private function initialize()
  {
    $this->actualService = new Service1(); // This operation may take some time thus we deferred as long as possible
  }

  private function isInitialized()
  {
    return $this->actualService === null;
  }

  public function someActionOnThisService()
  {
    if (!$this->isInitalized()) {
      $this->initalize();
    }

    $this->actualService->someActionOnThisService();
  }

你有一个带延迟加载的简单代理对象。如果你想去那条路线,你可能想检查一下很棒的Proxy Manager Library

2)拆分控制器

如果你的控制器有太多的依赖关系,你可能想要拆分它。

事实上,您可能希望阅读Paul M. Jones(Aura框架的首席开发人员)关于MVC-Refinement的提案,即使您可能不完全同意,恕我直言仍然是一个很好的阅读。

即使您为了减少依赖关系而拆分控制器,延迟加载依赖关系也是一个好主意(显然,如果天气在您的环境中可行,则必须检查天气:为了获得更快的速度,需要更多工作)。

答案 4 :(得分:-3)

在尝试加载尚未加载的类之前,可能需要定义__autoload()函数。像:

function __autoload($className) {
    require "/path/to/the/class/file/$className.php";
}

我的例子非常简单,自动要求类定义所在的文件。 您还可以在该函数中使用if-else语句或switch语句,以便巧妙地适应您自己的情况。

当PHP找不到类定义,适用于__autoload()newclass_exists()等时,调用call_user_method()函数,绝对是您的依赖/家长班。如果在调用__autoload()之后仍然没有类定义,PHP将生成错误。

或者您可以更优雅地使用spl_autoload_register()功能代替__autoload()

有关详细信息,您可能希望看到: http://php.net/manual/en/function.autoload.php http://php.net/manual/en/function.spl-autoload-register.php