7

这可能不是最佳实践,但在 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.";
    }
}
4

4 回答 4

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

于 2012-04-12T15:04:18.803 回答
5

合乎逻辑的结论是,如果您尝试创建一个类的对象,它将继续扫描文件的其余部分以查找该类声明。如果它无法“解析”类(由于您扩展了一个不存在的类),它将返回到您尝试创建对象的行并告诉您该类不存在。

那么,为什么在找不到您扩展的类时不给您一个错误呢?

好吧,PHP 不知道您以后是否会包含一个包含 的文件FakeInvalidClass,并且在第 4 行说Fatal error: Class 'FakeInvalidClass' not found.

编辑: 但是,您以后不能包含FakeInvalidClass,因为Test已经被解析了。所以,PHP 仍然会在它无法执行的那一行给你错误。但是一个更有用的错误信息是把它们堆叠起来:

Class 'Test' not found (Class 'FakeInvalidClass' not found in /mysite/test.php on line 8) in /mysite/test.php on line 4

但是 PHP 不会堆积错误。

于 2012-04-12T14:37:37.547 回答
3

只是因为在您的第一种情况下,未加载“测试”类。在第二种情况下,类是加载但扩展无效

于 2012-04-12T14:32:14.113 回答
0

案例 1:您尝试创建 Test 类的对象,因此当它尝试创建对象时,是基类 FakeInvalid 类的扩展,因此在创建 Test 类时出错,说找不到。

案例 2:它首先尝试扩展基类并且没有找到它,所以给出了错误,说 FakeInvalidClass not found。

于 2012-04-12T14:38:57.563 回答