php 最佳实践,覆盖 __construct() 与提供 init() 方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8210561/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best practice, overriding __construct() versus providing init() method
提问by GordonM
When you are subclassing objects and want to extend the initialization code, there are two approaches. Overriding __construct(), and implementing an initialization method that your superclass constructor calls.
当您子类化对象并希望扩展初始化代码时,有两种方法。覆盖 __construct(),并实现超类构造函数调用的初始化方法。
Method 1:
方法一:
class foo
{
public function __construct ($arg1, $arg2, $arg3)
{
// Do initialization
}
}
class bar extends foo
{
public function __construct ($arg1, $arg2, $arg3)
{
parent::__construct ($arg1, $arg2, $arg3);
// Do subclass initialization
}
}
Method 2
方法二
class foo
{
public function init ()
{
// Dummy function
}
public function __construct ($arg1, $arg2, $arg3)
{
// Do subclass defined initialization
$this -> init ();
// Do other initialization
}
}
class bar extends foo
{
public function init ()
{
// Do subclass initialization
}
}
The documentation for Zend Framework seems to discourage overriding constructors and wants you to override init methods, where provided, but this somehow just doesn't feel right to me. Zend also tends to do a few things that I'm not happy with so I'm not sure if it should be used as an example of best practice. I personally think the first approach is the correct one but I've seen the second approach often enough to wonder if that's actually what I should be doing.
Zend Framework 的文档似乎不鼓励覆盖构造函数,并希望您覆盖提供的 init 方法,但这在某种程度上对我来说并不合适。Zend 还倾向于做一些我不满意的事情,所以我不确定是否应该将它用作最佳实践的示例。我个人认为第一种方法是正确的,但我经常看到第二种方法,想知道这是否真的是我应该做的。
Do you have any comments regarding overriding __construct? I know you have to be careful to remember to invoke the superclass constructor, but most programmers should be aware of that.
你对覆盖 __construct 有什么意见吗?我知道你必须小心记住调用超类构造函数,但大多数程序员应该意识到这一点。
EDIT:I'm not using Zend, I'm only using it as an example of a codebase that encourages you to use init() instead of overriding __construct().
编辑:我没有使用 Zend,我只是将它用作鼓励您使用 init() 而不是覆盖 __construct() 的代码库示例。
采纳答案by Frosty Z
Looks like the second approach is postponing the problem.
看起来第二种方法是推迟问题。
If you have a class:
如果你有一个类:
class bar2 extends bar // which already extends foo
{
public function init()
{
// You should then do anyway:
parent::init();
// ...
}
}
I would go for the first approach too, more logical and straightforward, since the parent::init()
or parent::__construct()
call could not be endlessly avoided. The first approach, IMO, is less confusing.
我也会采用第一种方法,更合乎逻辑和直接,因为无法无休止地避免parent::init()
orparent::__construct()
调用。第一种方法 IMO 不那么令人困惑。
回答by Gordon
The only two situations I can think of in which it makes sense to use init()
is when your constructor is non-public but you need to give people a chance to influence initialization, e.g. in an abstract Singleton (which you do not want to use anyway). Or, like in Zend Framework, when additionalinitialization should be defered (but then you don't call init()
from the constructor).
我能想到的唯一两种使用有意义的情况init()
是当你的构造函数是非公开的,但你需要给人们一个机会来影响初始化,例如在一个抽象的单例中(无论如何你都不想使用) . 或者,就像在 Zend Framework 中一样,应该推迟额外的初始化(但是您不会init()
从构造函数调用)。
Calling a method in a subclass from the superclass is called Template Method, by the way. The UseCase would be to orchestrate a certain workflow but allow the subtype to influence parts of it. This is usually done from regular methods though. Note that your constructor should not orchestrate anything but just initialize the object into a valid state.
顺便说一下,从超类调用子类中的方法称为Template Method。用例将编排某个工作流,但允许子类型影响其中的一部分。不过,这通常是通过常规方法完成的。请注意,您的构造函数不应编排任何内容,而应将对象初始化为有效状态。
You definitely should notcall/offer init()
from the constructor to prevent developers having to remember to call the supertype constructor. While that may sound convenient, it will quickly mess up the inheritance hierarchy. Also note that it deviates from how objects are usually initialized and developers have to learn this new behavior just like they have to learn to call the supertype's constructor.
你绝对应该不叫/报价init()
从构造以防止不必记住调用父类的构造函数的开发。虽然这听起来很方便,但它很快就会弄乱继承层次结构。还要注意,它偏离了对象通常的初始化方式,开发人员必须学习这种新行为,就像他们必须学习调用超类型的构造函数一样。
回答by Jake N
Firstly
首先
Zend also tends to do a few things that I'm not happy with
Zend 也倾向于做一些我不满意的事情
You can solve this simply, by not using it.
您可以通过不使用它来简单地解决此问题。
But secondly and more importantly you should override init()
and not __construct()
because init()
is part of the dispatch operation that Zend uses and using it ensures that the rest of your App is there and in place. Doing otherwise breaks the flow of Zend's MVC model and may result in odd behaviour.
但其次更重要的是你应该覆盖init()
而不是__construct()
因为它init()
是 Zend 使用的调度操作的一部分,并使用它确保你的应用程序的其余部分都在那里并就位。否则会破坏 Zend 的 MVC 模型的流程,并可能导致奇怪的行为。
Edit
编辑
I think the main reason for me is that it stops other developers from fiddling. You can do anything with init()
but not with __construct()
as this needs to run correctly with all the correct params in place.
我认为对我来说主要原因是它阻止了其他开发人员摆弄。你可以做任何事情,init()
但不能做任何事情,__construct()
因为这需要在所有正确的参数到位的情况下正确运行。
This is from the Zend Docs:
这是来自 Zend 文档:
While you can always override the action controller's constructor, we do not recommend this. Zend_Controller_Action::_construct() performs some important tasks, such as registering the request and response objects, as well as any custom invocation arguments passed in from the front controller. If you must override the constructor, be sure to call parent::_construct($request, $response, $invokeArgs).
虽然您始终可以覆盖动作控制器的构造函数,但我们不建议这样做。Zend_Controller_Action::_ construct() 执行一些重要的任务,例如注册请求和响应对象,以及从前端控制器传入的任何自定义调用参数。如果必须覆盖构造函数,请务必调用 parent::_construct($request, $response, $invokeArgs)。
回答by MW.
I would use the init function because if you override the constructor you (normally) have to remember to call the parent constructor at the top of your child class's constructor. While you may be aware of that, you can not guarantee that another developer tasked with maintining your application will be.
我会使用 init 函数,因为如果您覆盖构造函数,您(通常)必须记住在子类的构造函数顶部调用父构造函数。虽然您可能知道这一点,但您不能保证其他负责维护您的应用程序的开发人员会这样做。
回答by Savageman
I can see one benefit from using init()
instead of __construct()
: if the signature changes in the constructor, you will have to update every derived class to match the new signature.
我可以看到使用init()
而不是的一个好处__construct()
:如果构造函数中的签名发生变化,您将必须更新每个派生类以匹配新签名。
If init()
has no parameter, this won't happen.
如果init()
没有参数,则不会发生这种情况。