它可能不是最佳实践,但在
PHP中我们可以在文件底部定义类但是,
- $t = new Test();
- $t->foo();
- class Test extends FakeInvalidClass {
- public function foo(){
- echo "arrived in foo.";
- }
- }
致命错误:第4行/mysite/test.PHP中未找到“测试”类
这很奇怪……类’Test’在文件的底部定义,PHP应该失败,因为找不到FakeInvalidClass,而不是Test
产生更人性化的错误
致命错误:第4行的/mysite/test.PHP中找不到类’FakeInvalidClass’
作为参考,这很好用:
我认为当你看到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(参见返回: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’代码,但该类不存在,因此它返回一个FakenInvalidClass 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,'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’测试’代码并正常执行.
这可以解释为PHP将在执行代码之前解析它在代码中遇到的第一级类.当您创建扩展另一个类或实例化对象的类定义时,将在代码中的该点为该类插入ZEND_FETCH_CLASS操作码.它实际上是懒惰初始化.
这也可以通过以下方式得到证明:
- <?PHP
- exit;
- class Test extends FakeInvalidClass {
- public function foo(){
- echo "arrived in foo.";
- }
- }
结论:
ZEND_FETCH_CLASS操作码的不同参数解释了不同的错误消息.
现在,如果你想知道为什么ZE会生成这样的操作码,它可能是一个设计选择,它可能更容易维护.但说实话,我不知道.