Php 这是依赖注入吗?这是一种糟糕的做法吗?
我有一个小框架,我这样编码。我不确定它是否被称为依赖注入。我不知道它是否像一个设计模式。我也不知道,也不知道作为param传递Php 这是依赖注入吗?这是一种糟糕的做法吗?,php,oop,dependency-injection,Php,Oop,Dependency Injection,我有一个小框架,我这样编码。我不确定它是否被称为依赖注入。我不知道它是否像一个设计模式。我也不知道,也不知道作为param传递$this是否是一种不好的做法 看看这个,;(不是一个有效的示例,只是将这些代码写入浏览器中进行解释。) 基本上,我的控制器可以通过引擎模型访问任何模型。我相信依赖注入就是将依赖注入控制器?就像,我的注册控制器需要一个数据库模型、路由模型和模板模型来工作。这里有它所依赖的一切。我弄错了吗 话虽如此,我的问题是: 这是一个有效的依赖注入示例吗?如果没有,是什么?它在设计模
$this
是否是一种不好的做法
看看这个,;(不是一个有效的示例,只是将这些代码写入浏览器中进行解释。)
基本上,我的控制器可以通过引擎模型访问任何模型。我相信依赖注入就是将依赖注入控制器?就像,我的注册控制器需要一个数据库模型、路由模型和模板模型来工作。这里有它所依赖的一切。我弄错了吗 话虽如此,我的问题是:
$this
参数是一种糟糕的做法吗?若然,原因为何FrameWork\u Engine\u模型是一个注册表()。将注册表作为依赖项注入所有对象是一种误解的依赖项注入。从技术上讲,它是DI,但是您创建了一个从所有事物到所有事物的依赖关系,并且剥夺了DI应该提供的灵活性
FrameWork\u Engine\u模型
旨在实例化服务并管理它们的依赖关系,您可以将其更改为(与DI相关的典型模式)public function createRegisterController()
{
$controller = new RegisterController();
$controller->setImage($this->getImageService());
// ...
return $controller;
}
public function getImageService()
{
if ($this->imageService === null) {
$this->imageService = new Image();
// inject dependencies of Image here
}
return $this->imageService;
}
这里重要的一点是:只注入所需的依赖项。不要创建一堆伪装成DI的全局变量。您就快到了
问题1
不,我不认为它是一个有效的依赖注入示例。它有点像服务定位器(因为您将整个容器注入到您的服务中,并使用它来“定位”依赖的服务)
问题2
您在依赖项注入和依赖项注入容器之间制造了一个小的混淆
首先,依赖项注入意味着在运行时将依赖项推送到对象中,而不是创建/拉取它们
举例来说:
//hardcoded dependecies
class BadService
{
public function __construct()
{
$this->dep1 = new ConcreteObject1();
$this->dep2 = new ConcreteObject2();
}
}
因此,在上面的示例中,BadService
使得在运行时连接其他依赖项变得不可能,因为它们已经被硬拉入构造函数本身
//service locator pattern
class AlmostGoodService
{
public function __construct(Container $container)
{
$this->dep1 = $container->getADep1();
$this->dep2 = $container->getADep2();
}
}
在AlmostGoodService
示例中,我们已经从前面的示例中删除了硬依赖项,但是我们仍然依赖于容器的特定实现(这意味着如果不为该容器提供实现,我们的服务是不可重用的)。这是一个与您正在做的事情相匹配的示例
//dependecy injection
class GoodService
{
public function __construct($dep1, OptionalInterface $dep2)
{
$this->dep1 = $dep1;
$this->dep2 = $dep2;
}
}
GoodService
服务不涉及其具体依赖项的创建,并且可以在运行时轻松地与实现$dep1
的“协议”或$dep2
的可选接口的任何依赖项“连接”(因此,名称-依赖项注入背后的基本概念).
进行此接线的部件称为a
现在,以最简单的形式,a只不过是一个能够在运行时基于某种形式的配置连接对象的对象
我说过,您已经快到了,但您的实施存在一些问题:
/* This is the revised engine model */
class FrameWork_Engine_Model
{
function __construct($config)
{
$this->config = $cofig;
}
public function database()
{
require_once('Database.class.php');
return new Database($this->config['configParams']);
}
public function bbcode()
{
require_once('BBCode.class.php');
return new BBCode($this->database());
}
public function image()
{
require_once('Image.class.php');
$this->image = new Image($this->config['extensionName']);
}
....
public function register_controller($shared = true)
{
if ($shared && $this->register_controller) {
return $this->register_controller;
}
return $this->register_controller = new Register_Controller($this->database(), $thus->image(), $this->bbcode());
}
}
- 连接应该是惰性的(您不想让所有这些都在构造函数中工作,因为随着应用程序的增长,它会大大降低速度)
- 您不应该将整个容器(
)作为依赖项传递,因为这样您就会退回到较弱的容器,即。相反,您应该将具体的依赖项传递给您的服务构造函数$this
$container
作为依赖项传递给服务(即控制器或惰性服务工厂),但通常最好不要使用这种做法,因为它将使您的服务更易于重用和测试。当您觉得您的服务有太多依赖项时,这是一个好迹象,表明您的服务做得太多,现在是拆分它的好时机
原型容器实现
因此,根据我上面的回答,这里是一个经过修改的(远不完美的)实现:
/* This is the revised engine model */
class FrameWork_Engine_Model
{
function __construct($config)
{
$this->config = $cofig;
}
public function database()
{
require_once('Database.class.php');
return new Database($this->config['configParams']);
}
public function bbcode()
{
require_once('BBCode.class.php');
return new BBCode($this->database());
}
public function image()
{
require_once('Image.class.php');
$this->image = new Image($this->config['extensionName']);
}
....
public function register_controller($shared = true)
{
if ($shared && $this->register_controller) {
return $this->register_controller;
}
return $this->register_controller = new Register_Controller($this->database(), $thus->image(), $this->bbcode());
}
}
现在,要使用您的服务:
$container = new FrameWork_Engine_Model();
$container->register_controller()->doSomeAction()
还有什么可以改进的?您的容器应:
- 提供一种共享服务的方式,即只初始化一次服务
- be-提供一种在配置后锁定它的方法
- 能够与其他容器“合并”——这样您的应用程序将真正模块化
- 容许
- 容许
- 支持
- -PHP5.3轻量级DI容器
- -PHP5.3功能完整DI容器
- -小型PHP 5.2 DI容器
$container = new FrameWork_Engine_Model();
$container->register_controller()->doSomeAction()