在PHP的詞法分析時(shí),$this變量是符合其規(guī)則的,在語法解析生成中間代碼時(shí),PHP內(nèi)核會根據(jù)變量類型在生成賦值的中間代碼時(shí)判斷是否為$this變量,如果是則報(bào)錯(cuò)。這里為什么要報(bào)錯(cuò)呢?因?yàn)閠his作為一個(gè)特殊的變量,在對象的成員方法等調(diào)用初始化時(shí)會將this變量添加到活動符號表。
在類的成員方法里面,可以用 ->(對象運(yùn)算符):$this->property(其中 property 是該屬性名)這種方式來訪問非靜態(tài)屬性。
當(dāng)一個(gè)方法在類定義內(nèi)部被調(diào)用時(shí),有一個(gè)可用的偽變量 $this。$this 是一個(gè)到主叫對象的引用(通常是該方法所從屬的對象,但如果是從第二個(gè)對象靜態(tài)調(diào)用時(shí)也可能是另一個(gè)對象)。
在詞法分析、語法分析并生成中間代碼時(shí),$this作為一個(gè)特殊的變量存在,特別是在生成中間代碼時(shí),代碼中充斥著對于this的特殊處理。這些都是為后面的運(yùn)行做準(zhǔn)備,如識別標(biāo)記出某處使用this變量,在存儲opcode的zend_op_array結(jié)構(gòu)體中專門有一個(gè)變量this_var標(biāo)識是否有this變量。一個(gè)函數(shù)或一個(gè)類方法都會生成一個(gè)新的zend_op_array,在生成中間代碼時(shí),判斷當(dāng)前變量是否為this變量。
this變量在執(zhí)行過程中會有兩種存在狀態(tài),一種是全局傳遞的狀態(tài),存儲在EG(This),一種是當(dāng)前作用域狀態(tài),以this變量存儲在EG(active_symbol_table)(當(dāng)前執(zhí)行環(huán)境的活動符號表)。
在我們執(zhí)行一個(gè) op_array 時(shí),比如一個(gè)對象的方法,PHP內(nèi)核會給這個(gè) op_array 生成一個(gè) zendexecutedata ,在生成初始化時(shí),EG(This) 會添加到EG(active_symbol_table) 。
在方法調(diào)用過程中,如果有用到this變量,則會直接取EG(active_symbol_table)的值。
那么一個(gè)對象中的EG(This)在哪里初始化呢?
就EG(This)變量本身來說,在我們初始化PHP的執(zhí)行環(huán)境時(shí),它和其它全局變量(如EG(scope)等)一樣都會被初始化為NULL。
對于一個(gè)對象來說,當(dāng)我們創(chuàng)建了一個(gè)對象,調(diào)用時(shí),PHP內(nèi)核會將當(dāng)前獲得的對象直接賦值給EG(This),而這個(gè)當(dāng)前獲得的對象是在通過new操作生成對象時(shí)創(chuàng)建的對象本身。
如下這個(gè)簡單示例:
- class Foo {
- public $var = 10;
- function t() {
- echo $this->var;
- }
- function t2() {
- echo 33;
- }
- }
- $foo = new Foo();
- $foo->t();
其主程序流程生成的中間代碼如下:
- function name: (null)
- number of ops: 8
- compiled vars: !0 = $foo
- line # * op fetch ext return operands
- ---------------------------------------------------------------------------------
- 2 0 > NOP
- 15 1 ZEND_FETCH_CLASS 4 :1 'Foo'
- 2 NEW $2 :1
- 3 DO_FCALL_BY_NAME 0
- 4 ASSIGN !0, $2
- 16 5 ZEND_INIT_METHOD_CALL !0, 't'
- 6 DO_FCALL_BY_NAME 0
- 7 > RETURN
- 1this
變量原始的對象值出生在 opcode NEW,經(jīng)過了賦值(ASSIGN)后,在方法初始化時(shí),將變量本身傳遞給執(zhí)行環(huán)境的調(diào)用者,調(diào)用者又在執(zhí)行調(diào)用(DO_FCALL_BY_NAME)時(shí)將變量傳遞給EG(This),當(dāng)執(zhí)行這個(gè)方法的op_array時(shí),初始化當(dāng)前作用域的環(huán)境(zend_execute_data)時(shí),會將EG(This)作為$this變量添加到活動符號表,后續(xù)方法中的$this變量的使用就會直接取符號表的變量。
新聞熱點(diǎn)
疑難解答