PHP5多層繼承順序的bug

2021-07-04 19:20:17 字數 4777 閱讀 4880

·        

作者: 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,從字面上比較好理解,是指這,自己,父親,...