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

FakeInvalidClassそれは奇妙なことです...クラス'Test'はファイルの下部に定義されていますが、PHPは見つからなかったために失敗したはずですが、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がコードで検出した第1レベルのクラスを実行するに解析するという事実によって説明されます。別のクラスを拡張するクラス定義を作成するか、オブジェクトをインスタンス化する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

最初のケースでは、クラス「Test」がロードされていません。2番目のケースでは、クラスはロードされていますが、拡張は無効です

于 2012-04-12T14:32:14.113 に答える
0

ケース1:クラスTestのオブジェクトを作成しようとしたため、オブジェクトを作成しようとすると、基本クラスFakeInvalidクラスからの拡張機能が作成されたため、Testクラスの作成中にエラーが発生しました。

ケース2:最初に基本クラスを拡張しようとしましたが、見つからなかったため、FakeInvalidClassが見つかりませんというエラーが表示されます。

于 2012-04-12T14:38:57.563 に答える