如何将实例引入基类

时间:2014-03-15 14:11:12

标签: php oop model-view-controller service-locator service-provider

我正在用PHP构建一个简单的MVC框架,而我却陷入了必须创建BaseController类的部分。

每个"页面"控制器需要从此BaseController扩展。因为这个BaseController类将具有允许用户访问template引擎和Logger类(以及其他一些东西)的属性。

我遇到的问题是我不确定如何在BaseController类中实例化这些东西。我显然可以在这样的__constructo()中进行硬编码:

class BaseController
{
    protected $view;
    protected $log;

    public function __construct()
    {
        $this->view = new \namespace\view('param1', 'param2');
        $this->log = new Logger('name');
        $this->log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
    }
}

但这并不能使它非常模块化。例如,它很难改变Logger类。或者,如果用户想要将模板引擎更改为Smarty,例如。

我也不能真正使用一种Dependancy Injection形式。因为从BaseController扩展的每个控制器都必须将这些实例传递给BaseController

这看起来像这样:

class BaseController
{
    protected $view;
    protected $log;

    public function __construct($view, $log)
    {
        $this->view = $view;
        $this->log = $log;
    }
}

的HomeController

class HomeController extends BaseController
{
    public function __construct($view, $log)
    {
        parent::__construct($view, $log);

        // Do my own stuff
    }
}

对于我来说,当用户只想在__constructor中做一件简单的事情时,它并不是真正用户友好的。甚至没有IoC

所以我现在唯一能想到的就是使用Service Provider__construct方法的BaseController。但我不确定这是不是可行的方法?也许有更好的选择?

那么解决这个问题的解决方案是什么?

PS。如果我确实需要Service Locator,那么还有 好的 示例吗?我发现的那些是由那些似乎并不真正知道他们在谈论什么的人写的。他们基本上是互相复制博客文章。

1 个答案:

答案 0 :(得分:1)

您首先需要考虑控制器的责任,为什么需要访问日志记录功能,或者为什么要设置模板引擎或切换模板?

控制器工作只是从请求中提取数据(主要是表单数据/用户输入)并通过服务将其发送到模型层,它不应该选择模板,即视图作业。

您显然希望将基本控制器的依赖关系保持在最低限度,以便在实例化子控制器时,您不会有大量依赖项要注入。

我的基本控制器有两个依赖项,请求对象和一个视图都注入。控制器简单明了,没有逻辑或任何花哨的东西都应该发生在它们中。有一次我不得不在我的一个控制器中使用记录器,但这只是因为PayPal正在使用IPN系统向它发送请求,我需要将请求中的所有数据记录到文件中以查看发生了什么,除了这样的特殊情况,我无法理解为什么控制器需要记录器。在这种情况下,只有处理PayPal请求的控制器持有记录器的实例,而不是父基本控制器。

您应始终注入依赖项。不要在构造函数中实例化对象,它会使您的类与这些对象紧密耦合。

如果您最终使用服务定位器,则可能表明您的类违反了OOP的单一责任原则。

控制器应该是简单的,不要通过添加您认为将来可能需要的依赖项来使它们复杂化,特别是不要对基本控制器进行复制,否则您可能需要进行大量的重构。