为什么在调用父级构造函数时会出现致命错误?
我正在扩展 SPL(标准 PHP 库)类之一,但无法调用父类的构造函数。这是我收到的错误:
致命错误:无法调用构造函数
以下是 SplQueue
文档的链接:http://www.php.net/manual/en/class.splqueue.php
这是我的代码:
$queue = new Queue();
class Queue extends SplQueue {
public function __construct() {
echo 'before';
parent::__construct();
echo 'I have made it after the parent constructor call';
}
}
exit;
什么可以阻止我调用父级的构造函数?
I am extending one of the SPL (Standard PHP Library) classes and I am unable to call the parent's constructor. Here is the error I am getting:
Fatal error: Cannot call constructor
Here is a link to the SplQueue
's documentation: http://www.php.net/manual/en/class.splqueue.php
Here is my code:
$queue = new Queue();
class Queue extends SplQueue {
public function __construct() {
echo 'before';
parent::__construct();
echo 'I have made it after the parent constructor call';
}
}
exit;
What could prevent me from calling the parent's constructor?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
SplQueue
继承自SplDoublyLinkedList
。这些类都没有定义自己的构造函数。因此,没有显式的父构造函数可供调用,并且您会收到这样的错误。该文档对此有一点误导(因为它对于许多 SPL 类来说)。要解决该错误,请不要调用父构造函数。
现在,在大多数面向对象的语言中,如果类中没有声明显式构造函数,您将期望调用默认构造函数。但这里有一个问题:PHP 类没有默认构造函数!当且仅当定义了一个构造函数时,类才具有构造函数。
事实上,使用反射来分析
stdClass
类,我们甚至发现它缺少构造函数:尝试反射
SplQueue
和SplDoublyLinkedList
的构造函数也产生NULL
。我的猜测是,当您告诉 PHP 实例化一个类时,它会执行新对象所需的所有内部内存分配,然后查找构造函数定义并调用它仅当定义为
__construct() 或
()
。我去查看了源代码,似乎 PHP 在找不到要调用的构造函数时会崩溃并死掉,因为您在子类中明确地告诉了它(请参阅 zend_vm_def.hzend_vm_def.h)代码>)。SplQueue
inherits fromSplDoublyLinkedList
. Neither of these classes defines a constructor of its own. Therefore there's no explicit parent constructor to call, and you get such an error. The documentation is a little misleading on this one (as it is for many SPL classes).To solve the error, don't call the parent constructor.
Now, in most object-oriented languages, you'll expect the default constructor to be called if there isn't an explicit constructor declared in a class. But here's the catch: PHP classes don't have default constructors! A class has a constructor if and only if one is defined.
In fact, using reflection to analyze the
stdClass
class, we see even that lacks a constructor:Attempting to reflect the constructors of
SplQueue
andSplDoublyLinkedList
both yieldNULL
as well.My guess is that when you tell PHP to instantiate a class, it performs all the internal memory allocation it needs for the new object, then looks for a constructor definition and calls it only if a definition of
__construct()
or<class name>()
is found. I went to take a look at the source code, and it seems that PHP just freaks out and dies when it can't find a constructor to call because you told it explicitly to in a subclass (seezend_vm_def.h
).通常,当
parent::__construct()
中引用的parent
类实际上没有__construct()
函数时,就会引发此错误。This error gets thrown, usually, when the
parent
class being referenced inparent::__construct()
actually has no__construct()
function.如果要调用最近祖先的构造函数,可以使用 循环祖先class_parents 并检查 method_exists 是否有构造函数。如果是,则调用构造函数;如果没有,则继续搜索下一个最近的祖先。您不仅可以防止覆盖父级的构造函数,还可以防止覆盖其他祖先的构造函数(如果父级没有构造函数):
为了代码重用,您还可以将此代码编写为函数,将 PHP 代码返回为 <代码>评估:
If you want to call the constructor of the nearest ancestor, you can loop through the ancestors with class_parents and check with method_exists if it has a constructor. If so, call the constructor; if not, continue your search with the next nearest ancestor. Not only do you prevent overriding the parent's constructor, but also that of other ancestors (in case the parent doesn't have a constructor):
For code reuse, you could also write this code as a function that returns the PHP code to be
eval
ed:你可以像这样破解它:
但它是无助的。
只需为每个类显式声明构造函数即可。这是正确的行为。
You may hack it like this:
but it's helpless.
just declare constructor explicitly for every class. it's the right behavior.
我遇到了同样的错误。我通过在父类中定义一个空构造函数解决了这个问题。这样其他类就不必定义它。我认为这是更干净的方法。
如果您仍然需要调用构造函数,您可以这样做。
I got the same error. I have solved it by defining an empty constructor in the parent class. That way other classes don't have to define it. I think it's cleaner approach.
If you still need to call the constructor you can do this.