什么事情最好不要在构造函数中完成?

时间:2009-02-07 21:48:41

标签: php oop constructor

我首先提出了一个问题:“在构造函数上执行单元测试的最佳方法是什么(例如,PHP5中的__construct())”,但在阅读相关问题时,我看到了几条似乎是建议在构造函数中设置成员变量或执行任何复杂的操作都是no-nos。

这里讨论的类的构造函数接受一个参数,对它执行一些操作(确保它通过嗅探测试,并在必要时进行转换),然后将其存储在成员变量中。

我认为这样做的好处是:

1)客户端代码永远是     肯定有这个价值     每当一个对象成员变量     该类的实例化,

2)它在客户端代码中保存了一个步骤     (其中一个可以想象得到     错过了,例如,

$Thing = new Thing;
$Thing->initialize($var);

当我们可以这样做时

$Thing = new Thing($var);

并完成它。

这是不是吗?如果是这样的话?

10 个答案:

答案 0 :(得分:16)

我的经验法则是在构造函数完成后,对象应该可以使用了。但是经常有很多选项可以在之后进行调整。

我的做和卖的清单:

  • 构造函数应为对象设置基本选项。
  • 他们应该创建帮助对象的实例。
  • 他们应该 aqquire资源(文件,套接字......),除非该对象显然是某个资源的包装。

当然,没有例外的规则。重要的是你要考虑你的设计和你的选择。使对象使用自然 - 包括错误报告。

答案 1 :(得分:8)

这在C ++讨论中出现了很多,我得到的一般结论是:

如果某个对象没有获取任何外部资源,则必须在构造函数中初始化成员。这涉及在构造函数中完成所有工作。

  • (x,y)坐标(或者实际上任何其他只是一个美化元组的结构)
  • 美国州名缩写查找表

如果一个对象获得了它可以控制的资源,那么可能在构造函数中分配

  • 打开文件描述符
  • 已分配内存
  • 处理/指向外部库的指针

如果对象获取了无法完全控制的资源,则必须分配在构造函数外部

  • TCP连接
  • 数据库连接
  • 弱参考

总有例外,但这涵盖了大多数情况。

答案 2 :(得分:6)

构造函数用于初始化对象,所以

$Thing = new Thing($var);

完全可以接受。

答案 3 :(得分:4)

构造函数的工作是建立一个实例invariants

任何对此没有贡献的东西最好不要在构造函数之外。

答案 4 :(得分:2)

为了提高类的可测试性,保持它的构造函数尽可能简单并让它只询问它绝对需要的东西通常是一件好事。作为谷歌“清洁代码会谈”系列的一部分,YouTube上有一个很棒的presentation可以详细解释这一点。

答案 5 :(得分:1)

你绝对应该避免让客户打电话

$thing->initialize($var)

那种东西绝对属于构造函数。客户端程序员让他们调用它是不友好的。有一种(略有争议的)思想流派认为你应该编写类,以便对象从不处于无效状态 - 并且'未初始化'是无效状态。

但是出于可测试性和性能原因,有时最好将某些初始化推迟到对象生命的后期。在这些情况下,懒惰评估是解决方案。

将Java语法放在Python答案中的道歉但是:

// Constructor
public MyObject(MyType initVar) {
      this.initVar = initVar;
}

private void lazyInitialize() {
    if(initialized) {
        return
    }
    // initialization code goes here, uses initVar
}

public SomeType doSomething(SomeOtherType x) {
    lazyInitialize();
    // doing something code goes here
}

您可以对延迟初始化进行细分,以便只初始化需要它的部分。例如,在吸气剂中这样做很常见,只是因为影响了价值的因素。

答案 6 :(得分:0)

取决于您尝试构建的系统类型,但总的来说,我认为构造函数最好只用于初始化对象的“状态”,而不是自己执行任何状态转换。最好只设置默认值。

然后我在我的对象中编写一个“handle”方法来处理用户输入,数据库调用,异常,整理等任何事情。这个想法是,这将根据外部力量(用户输入,时间等)处理对象所处的任何状态。基本上,所有可能改变对象状态并需要额外操作的事物都会被发现并在对象

最后,我将一个render方法放入类中,向用户显示有意义的内容。这仅表示用户的对象状态(无论可能是什么。)

__构建体($参数)
手柄()
渲染(例外$ ex = null)

答案 7 :(得分:0)

__construct魔术方法可以使用。您在许多框架和应用程序中看到初始化的原因是因为该对象正被编程到接口或者它正在尝试实现singleton / getInstance模式。

这些对象通常被拉入上下文或控制器,然后由其他更高级别的对象调用它们的公共接口功能。

答案 8 :(得分:0)

如果$ var绝对需要$ Thing才能工作,那么它是 DO

答案 9 :(得分:-1)

你不应该把东西放在一个只在创建类时才应该运行一次的构造函数中。

解释。

如果我有数据库类。其中构造函数是与数据库的连接 所以

$db = new dbclass;

现在我已连接到数据库了。

然后我们有一个在数据库类中使用某些方法的类。

class users extends dbclass
{
    // some methods
}

$users = new users 
// by doing this, we have called the dbclass's constructor again