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がそのようなオペコードを生成するのか疑問に思うなら、それはおそらく設計上の選択であり、おそらく保守が容易です。でも正直なところ、わかりません。