当我遇到这段代码时,我正在阅读一篇博客文章:
<?php
include_once 'config.php';
class User
{
//Database connect
public function __construct()
{
$db = new DB_Class();
}
在评论中,有人发布了以下内容:
永远不要在构造函数中启动数据库连接
但与所有评论战士一样,他们从不给出原因?为什么这是错误的或不好的做法?
在构造函数中工作,例如:创建/初始化协作者,与其他服务通信,以及设置自己的状态的逻辑删除测试所需的接缝,强制子类/模拟继承不需要的行为。构造函数中的过多工作会阻止实例化或更改测试中的协作者。
相反,使用依赖注入并将任何协作者传递给构造函数。这将创建更容易测试的代码。当您在 ctor 中进行某些操作时,使用Test Doublenew
模拟/存根要困难得多。
此外,通过注入协作者,您可以更轻松地更换具有不同实现的协作者,从而减少耦合,促进代码重用和针对接口而不是具体实现进行编码。
将数据库的实例传递给称为“依赖注入”的构造函数。这样做是为了解耦对象,这意味着降低对象之间的依赖关系。解耦的好处之一是系统具有更大的灵活性、更容易维护和编写单元测试。
但是,如果您使用设计模式、实践测试驱动开发和明确定义的架构(例如在域驱动设计中实践)来构建软件,您可以享受所有这些好处。
但是,如果您只是开始探索开发软件的 OOP 方式或刚开始学习一般的编程 - 也许您现在不应该为这些问题烦恼。
我认为在构造函数中初始化数据库连接违反了构造函数的一般合同。当您new User()
希望获得描述用户的对象时。如果这需要一个有效的数据库连接,如果建立连接失败,对象的状态是什么?构造函数不应该抛出异常,因为它的唯一目的是确保正确的对象状态。(至少这是我的观点......我知道其他人不认为构造函数的异常是坏的。但是,我这样做。)
此外:如果数据库连接被封装在一个对象中,则不能重用它。
在这种特殊情况下,可能是处理用户数据的模型,它可能非常有用。但是如果你突然想要这个类是可移植的并且可以使用不同的数据库呢?当我想将我的用户管理器类用于不同的项目时,我自己也遇到了这个问题。