这可能不是最佳做法,但在PHP中我们可以在文件底部定义类但是,
$t = new Test();
$t->foo();
class Test extends FakeInvalidClass {
public function foo(){
echo "arrived in foo.";
}
}
生成错误消息:
Fatal error: Class 'Test' not found in /mysite/test.php on line 4
这很奇怪......类'Test'在文件的底部定义,PHP应该失败,因为找不到FakeInvalidClass
,而不是Test
<?php
// test.php
class Test extends FakeInvalidClass {
public function foo(){
echo "arrived in foo.";
}
}
$t = new Test();
$t->foo();
产生更易读的错误
Fatal error: Class 'FakeInvalidClass' not found in /mysite/test.php on line 4
作为参考,这很好用:
<?php
// test.php
$t = new Test();
$t->foo();
class Test {
public function foo(){
echo "arrived in foo.";
}
}
答案 0 :(得分:6)
我认为当你看到Zend Engine为每个例子生成的操作码时(对我来说无论如何)都会对你有意义。
示例1:
compiled vars: !0 = $t
line # * op fetch ext return operands
---------------------------------------------------------------------------------
4 0 > EXT_STMT
1 ZEND_FETCH_CLASS :0 'Test'
2 EXT_FCALL_BEGIN
3 NEW $1 :0
4 DO_FCALL_BY_NAME 0
5 EXT_FCALL_END
6 ASSIGN !0, $1
6 7 EXT_STMT
8 ZEND_INIT_METHOD_CALL !0, 'foo'
9 EXT_FCALL_BEGIN
10 DO_FCALL_BY_NAME 0
11 EXT_FCALL_END
7 12 EXT_STMT
13 ZEND_FETCH_CLASS :6 'FakeInvalidClass'
14 ZEND_DECLARE_INHERITED_CLASS $7 '%00test%2Fhome%2Fflacroix%2Ftest.php0x7f756fea4055', 'test'
12 15 > RETURN 1
正如您所看到的那样,#1获得了Test
类,而后者又转到#13来获取FakeInvalidClass
(请参阅那里的return :6
)。由于后者未定义,#13失败并返回#1,这也失败,因为Test
未定义。
它们(#13和#1)都将调用zend_error
(如PHP源代码所示),但zend_error
具有全局状态(即:错误未堆叠),因此任何后续调用将使用新的错误消息覆盖错误消息。所以,在伪代码中:
ZEND_FETCH_CLASS('Test')
ZEND_FETCH_CLASS('FakeInvalidClass')
zend_error('Class FakeInvalidClass not found')
return
zend_error('Class Test not found')
return
示例2:
compiled vars: !0 = $t
line # * op fetch ext return operands
---------------------------------------------------------------------------------
4 0 > EXT_STMT
1 ZEND_FETCH_CLASS :0 'FakeInvalidClass'
2 ZEND_DECLARE_INHERITED_CLASS $1 '%00test%2Fhome%2Fflacroix%2Ftest2.php0x7fe2c1461038', 'test'
10 3 EXT_STMT
4 ZEND_FETCH_CLASS :2 'Test'
5 EXT_FCALL_BEGIN
6 NEW $3 :2
7 DO_FCALL_BY_NAME 0
8 EXT_FCALL_END
9 ASSIGN !0, $3
12 10 EXT_STMT
11 ZEND_INIT_METHOD_CALL !0, 'foo'
12 EXT_FCALL_BEGIN
13 DO_FCALL_BY_NAME 0
14 EXT_FCALL_END
13 15 > RETURN 1
此处#1是ZEND_FETCH_CLASS 'FakeInvalidClass'
代码,但该类不存在,因此它会返回FakeInvalidClass not found
消息。
示例3:
compiled vars: !0 = $t
line # * op fetch ext return operands
---------------------------------------------------------------------------------
4 0 > EXT_STMT
1 ZEND_FETCH_CLASS :0 'Test'
2 EXT_FCALL_BEGIN
3 NEW $1 :0
4 DO_FCALL_BY_NAME 0
5 EXT_FCALL_END
6 ASSIGN !0, $1
6 7 EXT_STMT
8 ZEND_INIT_METHOD_CALL !0, 'foo'
9 EXT_FCALL_BEGIN
10 DO_FCALL_BY_NAME 0
11 EXT_FCALL_END
8 12 EXT_STMT
13 NOP
13 14 > RETURN 1
Zend获取ZEND_FETCH_CLASS 'Test'
代码并正常执行。
这可以解释为PHP将在执行它之前解析它在代码中遇到的第一级类。当您创建扩展另一个类或实例化对象的类定义时,将在代码中的该点为该类插入ZEND_FETCH_CLASS
操作码。它实际上是延迟初始化。
事实证明,这也很有效:
<?php
exit;
class Test extends FakeInvalidClass {
public function foo(){
echo "arrived in foo.";
}
}
<强>结论:强>
不同的错误消息由ZEND_FETCH_CLASS
操作码的不同参数解释。
现在,如果你想知道为什么ZE会生成这样的操作码,它可能是一个设计选择,它可能更容易维护。但说实话,我不知道。
答案 1 :(得分:5)
逻辑上的结论是,如果您尝试创建类的对象,它将继续扫描文件的其余部分以获取此类声明。如果它无法解析&#39;该类(由于你扩展了一个不存在的类),它将返回到你试图创建该对象的行,并告诉你该类不存在。
那么为什么不在找不到你扩展的课程时给你一个错误呢?
嗯,PHP不知道你以后是否会包含一个包含FakeInvalidClass
的文件,在第4行说Fatal error: Class 'FakeInvalidClass' not found
是错误的。
修改强>
但是,由于FakeInvalidClass
已经被解析,因此您无法在Test
之后添加Class 'Test' not found (Class 'FakeInvalidClass' not found in /mysite/test.php on line 8) in /mysite/test.php on line 4
。因此,仍然存在PHP将在无法执行的行上给出错误。但是一个更具信息性的错误信息就是叠加它们:
{{1}}
但是PHP并没有堆叠错误。
答案 2 :(得分:3)
只是在第一种情况下,“Test”类没有加载。在第二种情况下,类是加载但扩展无效
答案 3 :(得分:0)
案例1: 你试图创建一个类Test的对象,所以当它试图从基类FakeInvalid类创建一个对象的扩展时,因此创建Test类的错误说它找不到。
案例2:它首先尝试扩展基类并且没有找到它,因此给出了错误,说未找到FakeInvalidClass。