【问题标题】:PHP design pattern using Dependancy Injection and shared variable?使用依赖注入和共享变量的 PHP 设计模式?
【发布时间】:2015-06-12 08:31:34
【问题描述】:

我将尽我所能解释这一点,如果部分内容没有完全理解,请原谅我。我正在构建一个用于教育目的的 PHP 库/框架。我正在使用单例模式构建它,但遇到了一些问题,并且最近似乎读到它不应该被使用,因为它不是很可测试,(虽然我不担心这是可测试的,但我想学习如何做),而应该使用依赖注入。

我想要的是一个共享变量,如果你愿意的话,它包含许多不同的类。例如 $app->database; $应用程序->视图; $应用程序->会话;等等,并且不确定我是否做对了。所有类也正在自动加载。

我有初始化主变量的 bootstrap/start.php(有这个名称吗?):

$app = new App(new Database, new Views, new Session);

在我主要使用的 App.php 类中:

 public $database;
 public $views;
 public $session

public function __construct(Client $client, Views $views, Session $session)
{
     $this->database = $database;
     $this->views = $views;
     $this->session = $session;
}

我的问题是:我应该像那样初始化构造函数中的所有类吗?还有一个大问题...我如何在我的 Views.php 类中使用 $database 变量而不创建一个可能会覆盖 Database 类中的某些属性的全新实例?

非常感谢您对此的一些见解。

【问题讨论】:

  • 作为其中一种方式,您可以在 App 中创建静态方法,这些方法将返回您的数据库、视图实例
  • 您应该寻找像PimpleSymfony 这样的容器,并创建ClientViews, Session` 服务。这样,容器包含每个服务的 1 个实例。现在对于依赖注入,如果View服务需要Database服务,你必须在他的构造函数中注入一个Databaseobject,并在他的服务声明中注入数据库service
  • @Med 感谢您的回复。我以前使用过 Symfony 容器,但想看看我是否可以从头开始自己解决一些问题。
  • 我同意@Med。如果您照常进行,则将您的应用程序与数据库/视图/会话的实现紧密联系在一起(顺便说一句,您可能并不总是需要会话)。拥有一个包含您可以使用的服务、工厂等的容器会更好。您可以在您的应用程序包中有一个接口,您的所有服务都将作为一个单独的接口实现,以保证应用程序/核心/无论您称之为包的任何人都可以使用它们(例如)

标签: php oop design-patterns dependency-injection


【解决方案1】:

关于类似 MVC 的架构,您真正应该了解的是,它们所基于的整个点称为关注点分离 (SoC)。

为什么你会在视图中访问数据库连接?显然是因为您想在此处执行查询并显示结果。这就是破坏 SoC 的原因。为了显示数据,您必须访问模型中的数据库连接,如果需要以某种方式解析,然后简单地将准备好的数组传递给视图,这样视图甚至不知道数据库这样的东西存在,他们只知道有一个数组,需要以某种方式显示。这种方法引入了一个主要优势 - 您可以轻松交换数据库引擎(使用 SOAP/REST、Mongo 等),而无需触及视图!

至于您的问题,您可以通过创建一个抽象类来解决这个问题,该类将被称为AbstractApplication 并将所有这些初始化逻辑放在那里。然后你可以简单地从这个基类继承。

另一种方法是使用所谓的服务定位器来处理它。您创建一个包装器,将所有依赖项放在那里,然后您只需为需要它的类注入服务定位器。这不是最好的方法,但它是处理大量依赖项列表的唯一干净方法(在现实世界场景中,您需要注入 4 个以上的参数)

【讨论】:

  • 我认为绑定数据库(模型)和视图(模板)需要控制器类
  • 1) 视图不是模板,而是由 UI 逻辑和模板组成的层。 2)模型不是一个类,而是由存储抽象和领域对象组成的抽象层。 3)他没有说这是MVC。正如我在一开始的回答中所说,SoC 都是关于类似 MVC 的架构
  • 控制器不负责从模型(服务)获取数据并将它们传递给视图。那不是MVC。您所指的称为 Model-View-Presenter
  • 是的模型负责它,但控制器制定逻辑并调用模型来做到这一点。
  • 检查这个: -- 查看:“嘿,控制器,用户刚刚告诉我他想删除第 4 项。”管制员:“嗯,在检查了他的凭据后,他可以这样做了……嘿,模特,我希望你得到第 4 项,然后做任何你想做的事情来删除它。”模型:“第 4 项……知道了。它被删除了。还给你,管制员。”控制器:“这里,我会收集新的数据集。返回给你,查看。”视图:“酷,我现在将新的集合展示给用户。” stackoverflow.com/questions/1015813/…
【解决方案2】:

您的代码看起来不错,但我建议您进行这些更改,将变量设为私有并生成 getter 和 setter。

<?php
Class App {

private $database;
private $views;
private $client;
private $session;

/**
 * 
 * @param type $database
 * @param type $views
 * @param type $client
 * @param type $session
 */
function __construct($database, $views, $client, $session) {
    $this->database = new $database;
    $this->views = new $views;
    $this->client = new $client;
    $this->session = new $session;
}

/**
 * 
 * @return type
 */
function getDatabase() {
    return $this->database;
}

/**
 * 
 * @return type
 */
function getViews() {
    return $this->views;
}

/**
 * 
 * @return type
 */
function getClient() {
    return $this->client;
}

/**
 * 
 * @return type
 */
function getSession() {
    return $this->session;
}

/**
 * 
 * @param type $database
 */
function setDatabase($database) {
    $this->database = $database;
}

/**
 * 
 * @param type $views
 */
function setViews($views) {
    $this->views = $views;
}

/**
 * 
 * @param type $client
 */
function setClient($client) {
    $this->client = $client;
}


/**
 * 
 * @param type $session
 */
function setSession($session) {
    $this->session = $session;
}

}
//and in bootstrap or where you loading just do this and make database, view and all other singleton.
$database = database::getInstance();
$views = views::getInstance();
$client = client::getInstance();
$session = session::getInstance();
$App = new App($database, $views, $client, $session);

【讨论】:

  • 你的改动很糟糕,因为:你违反了得墨忒耳法则,你推广了一种叫做紧耦合的坏做法
  • 我完全同意@DavidY 的观点,但我相信它是应用程序启动的应用程序的启动部分,我认为我们需要紧密耦合。
  • 无需紧耦合即可轻松完成。服务定位器来了,然后它被注入了
  • 是的,我完全理解,还有很多更好的方法,但这是其中之一,老实说,每种方法都有优点和缺点。如果需要,请随意编辑此代码以添加服务器定位器类。
猜你喜欢
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
  • 2015-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-18
相关资源
最近更新 更多