为什么PHP会为这两种情况输出不同的错误消息?

前端之家收集整理的这篇文章主要介绍了为什么PHP会为这两种情况输出不同的错误消息?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
它可能不是最佳实践,但在 PHP中我们可以在文件底部定义类但是,
  1. $t = new Test();
  2.  
  3. $t->foo();
  4.  
  5. class Test extends FakeInvalidClass {
  6. public function foo(){
  7. echo "arrived in foo.";
  8. }
  9. }

生成错误消息:

致命错误:第4行/mysite/test.PHP中未找到“测试”类

这很奇怪……类’Test’在文件底部定义,PHP应该失败,因为找不到FakeInvalidClass,而不是Test

  1. <?PHP
  2. // test.PHP
  3.  
  4. class Test extends FakeInvalidClass {
  5. public function foo(){
  6. echo "arrived in foo.";
  7. }
  8. }
  9.  
  10. $t = new Test();
  11.  
  12. $t->foo();

产生更人性化的错误

致命错误:第4行的/mysite/test.PHP中找不到类’FakeInvalidClass’

作为参考,这很好用:

  1. <?PHP
  2. // test.PHP
  3.  
  4. $t = new Test();
  5.  
  6. $t->foo();
  7.  
  8. class Test {
  9. public function foo(){
  10. echo "arrived in foo.";
  11. }
  12. }
我认为当你看到Zend Engine为每个例子生成的操作码时(对我来说无论如何)都会对你有意义.

例1:

  1. compiled vars: !0 = $t
  2. line # * op fetch ext return operands
  3. ---------------------------------------------------------------------------------
  4. 4 0 > EXT_STMT
  5. 1 ZEND_FETCH_CLASS :0 'Test'
  6. 2 EXT_FCALL_BEGIN
  7. 3 NEW $1 :0
  8. 4 DO_FCALL_BY_NAME 0
  9. 5 EXT_FCALL_END
  10. 6 ASSIGN !0,$1
  11. 6 7 EXT_STMT
  12. 8 ZEND_INIT_METHOD_CALL !0,'foo'
  13. 9 EXT_FCALL_BEGIN
  14. 10 DO_FCALL_BY_NAME 0
  15. 11 EXT_FCALL_END
  16. 7 12 EXT_STMT
  17. 13 ZEND_FETCH_CLASS :6 'FakeInvalidClass'
  18. 14 ZEND_DECLARE_INHERITED_CLASS $7 '%00test%2Fhome%2Fflacroix%2Ftest.PHP0x7f756fea4055','test'
  19. 12 15 > RETURN 1

正如你所看到的,#1获得了Test类,而后者又进入了#13来获取FakeInvalidClass(参见返回:6).由于后者未定义,#13失败并返回#1,这也因为Test未定义而失败.

它们(#13和#1)都将调用zend_error(如PHP代码所示),但zend_error具有全局状态(即:错误未堆叠),因此任何后续调用都将使用新错误覆盖错误消息.所以,在伪代码中:

  1. ZEND_FETCH_CLASS('Test')
  2. ZEND_FETCH_CLASS('FakeInvalidClass')
  3. zend_error('Class FakeInvalidClass not found')
  4. return
  5. zend_error('Class Test not found')
  6. return

例2:

  1. compiled vars: !0 = $t
  2. line # * op fetch ext return operands
  3. ---------------------------------------------------------------------------------
  4. 4 0 > EXT_STMT
  5. 1 ZEND_FETCH_CLASS :0 'FakeInvalidClass'
  6. 2 ZEND_DECLARE_INHERITED_CLASS $1 '%00test%2Fhome%2Fflacroix%2Ftest2.PHP0x7fe2c1461038','test'
  7. 10 3 EXT_STMT
  8. 4 ZEND_FETCH_CLASS :2 'Test'
  9. 5 EXT_FCALL_BEGIN
  10. 6 NEW $3 :2
  11. 7 DO_FCALL_BY_NAME 0
  12. 8 EXT_FCALL_END
  13. 9 ASSIGN !0,$3
  14. 12 10 EXT_STMT
  15. 11 ZEND_INIT_METHOD_CALL !0,'foo'
  16. 12 EXT_FCALL_BEGIN
  17. 13 DO_FCALL_BY_NAME 0
  18. 14 EXT_FCALL_END
  19. 13 15 > RETURN 1

这里#1是一个ZEND_FETCH_CLASS’FakeInvalidClass’代码,但该类不存在,因此它返回一个FakenInvalidClass not found消息,就像它应该的那样.

例3:

  1. compiled vars: !0 = $t
  2. line # * op fetch ext return operands
  3. ---------------------------------------------------------------------------------
  4. 4 0 > EXT_STMT
  5. 1 ZEND_FETCH_CLASS :0 'Test'
  6. 2 EXT_FCALL_BEGIN
  7. 3 NEW $1 :0
  8. 4 DO_FCALL_BY_NAME 0
  9. 5 EXT_FCALL_END
  10. 6 ASSIGN !0,'foo'
  11. 9 EXT_FCALL_BEGIN
  12. 10 DO_FCALL_BY_NAME 0
  13. 11 EXT_FCALL_END
  14. 8 12 EXT_STMT
  15. 13 NOP
  16. 13 14 > RETURN 1

Zend获取ZEND_FETCH_CLASS’测试’代码并正常执行.

这可以解释为PHP将在执行代码之前解析它在代码中遇到的第一级类.当您创建扩展另一个类或实例化对象的类定义时,将在代码中的该点为该类插入ZEND_FETCH_CLASS操作码.它实际上是懒惰初始化.

这也可以通过以下方式得到证明:

  1. <?PHP
  2.  
  3. exit;
  4.  
  5. class Test extends FakeInvalidClass {
  6. public function foo(){
  7. echo "arrived in foo.";
  8. }
  9. }

结论:

ZEND_FETCH_CLASS操作码的不同参数解释了不同的错误消息.

现在,如果你想知道为什么ZE会生成这样的操作码,它可能是一个设计选择,它可能更容易维护.但说实话,我不知道.

猜你在找的PHP相关文章