我认为当您看到 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 会生成这样的操作码,这可能是一种设计选择,它可能更容易维护。但老实说,我不知道。