·
作者: laruence()
·
: · 今天
guoxiaod
提出了乙個問題,如下:
1.
<?php
2.
class
a extends
b ;
4.
class
b extendsc;
6.
classc;
8.
?>
9.
會導致fatal error:
1.
php fatal error: class 'b' not found in /home/xinchen/1.php on line 2
2.
fatal error: class 'b' not found in /home/xinchen/1.phpon line 2
分析這個問題,是執行階段出錯,經過分析
php的編譯,執行過程,得出如下的
parsing順序…
1.
start:
2.
top_statement_list
3. ;
4.
5.
top_statement_list:
6.
top_statement_list
7.
.... //
有省略
8. ;
9.
10.
top_statement:
11.
.... //
有省略
12.
| class_declaration_statement
13.
.... //
有省略
14. ;
15.
16.
class_declaration_statement:
17.
unticked_class_declaration_statement
18. ;
19.
20.
unticked_class_declaration_statement:
21.
class_entry_typet_string extends_from
22.
.... //
有省略
23. ;
24.
25.
class_entry_type:
26.
t_class
27.
.... //
有省略
28. ;
29.
30.
extends_from:
31.
/* empty*/
32.
| t_extends fully_qualified_class_name
33.
.... //
有省略
34. ;
35.
fully_qualified_class_name:
36.
t_string
37. ;
1.
zend_do_fetch_class
會設定opcode = zend_fetch_class
從這個過程我們可以發現,這個應該是
php5
的bug,對於
fully_qualified_class_name
,如果fully_qualified_class_name
也是繼承來自乙個類,那麼就會出錯,
因為fully_qualified_class_name
只是簡單的去
fetch_class,
而如果這個時候,這個類還沒有被填入到
class_table
就會出錯。也就是說,需要有個機制,來保證父
class
首先被處理。
以下是我分析原始碼後的結論:對於a
,因為是個派生類,在編譯階段,當遇到它的定義的時候,會:
1.
zend_do_begin_class_declaration
在這個函式中,會呼叫:
1.
build_runtime_defined_function_key(&opline->op1.u.constant,lcname, name_len tsrmls_cc);
來產生乙個:
1.
sprintf
(result->value.str.val, "%c%s%s%s",'
\0',name, filename, char_pos_buf);
的字串,來做為乙個編譯器的
classname
存入class_table:
1.
zend_hash_update(cg
(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof
(zend_class_entry *), null);
最後在吸收
top_statement
的時候,會有一次類的生成(填入
class_table);
1.
top_statement:
2.
statement
3.
...
4.
| class_declaration_statement
5.
...
6.
...
7. ;
在zend_do_early_binding
的時候:
1.
void
zend_do_early_binding
(tsrmls_d)
9.
table=cg(
function_table);
10.
break;
11.
case
zend_declare_class:
12.
case
zend_declare_inherited_class:
13.
is_abstract_class=1;
14.
/* break missing intentionally */
15.
case
zend_verify_abstract_class:
21.
if(opline->opcode == zend_declare_class)
25.
}else
if(opline->opcode == zend_declare_inherited_class)
33. if(
do_bind_inherited_class
(opline,cg(
class_table), *pce, 1
tsrmls_cc) == null)
34.
37.
/* clear unnecessary zend_fetch_class opcode*/
38. }
看到了吧,如果找不到父類,就直接返回了,也就是說,派生類在編譯期如果找不到父類,就不會被真正初始化,而是推遲到執行期。會分配乙個
opcode
為zend_declare_inherited_class
的opline
,用來在執行期真正生成定義的類:
1.
zend_api zend_class_entry *
do_bind_inherited_class
(zend_op *
opline, hashtable *class_table, zend_class_entry *parent_ce, zend_bool compile_time tsrmls_dc)
2.
這個時候問題就來了:
因為我們的
b也是乙個派生類,所以在執行a的
do_bind_inherited_class
時候,對於
b,他也需要做乙個
zend_declare_inherited_class
,也就是說,此時的
class_table
中是沒有b的。
這也就解釋了,如果最基類
c,定義在前的時候,就不會出錯。
恩,這個應該是
php5
的乙個bug
。
公升級PHP5的理由 PHP4和PHP5效能對比
php 4到今年年底php group將不再對其進行支援了,所以為了讓大家更有信心的轉移到php 5平台上,我特別做了這個測試,看看我們php 4.x 是否真的效能比我們的php 5.x要好捏,測試結果很明顯,那就是php 5.x 比php 4.x不論是物件導向還是面向過程,都要比php 4.x 要...
php5中this,self,parent的意義
php5是一具備了大部分物件導向語言的特性的語言,比php4有了很多的物件導向的特性,但是有部分概念也比較繞人,所以今天拿出來說說,說的不好,請高手見諒.閱讀本文,需要了解php5的物件導向的知識 首 先我們來理解三個關鍵字 this,self,parent,從字面上比較好理解,是指這,自己,父親,...
php5中this,self,parent的意義
php5是一具備了大部分物件導向語言的特性的語言,比php4有了很多的物件導向的特性,但是有部分概念也比較繞人,所以今天拿出來說說,說的不好,請高手見諒.閱讀本文,需要了解php5的物件導向的知識 首 先我們來理解三個關鍵字 this,self,parent,從字面上比較好理解,是指這,自己,父親,...