手冊上的一個有意思的小示例。
http://www.php.net/manual/zh/language.variables.basics.php
$this = 'text'; // error
$name = 'this';
$$name = 'text'; // sets $this to 'text'
echo $$name;
在PHP的詞法分析時,$this變量是符合其規則的,在語法解析生成中間代碼時,PHP內核會根據變量類型在生成賦值的中間代碼時判斷是否為$this變量,如果是則報錯。這裡為什麼要報錯呢?因為this作為一個特殊的變量,在對象的成員方法等調用初始化時會將this變量添加到活動符號表。
在類的成員方法裡面,可以用 ->(對象運算符):$this->property(其中 property 是該屬性名)這種方式來訪問非靜態屬性。
當一個方法在類定義內部被調用時,有一個可用的偽變量 $this。$this 是一個到主叫對象的引用(通常是該方法所從屬的對象,但如果是從第二個對象靜態調用時也可能是另一個對象)。
在詞法分析、語法分析並生成中間代碼時,$this作為一個特殊的變量存在,特別是在生成中間代碼時,代碼中充斥著對於this的特殊處理。這些都是為後面的運行做准備,如識別標記出某處使用this變量,在存儲opcode的zend_op_array結構體中專門有一個變量this_var標識是否有this變量。一個函數或一個類方法都會生成一個新的zend_op_array,在生成中間代碼時,判斷當前變量是否為this變量。
this變量在執行過程中會有兩種存在狀態,一種是全局傳遞的狀態,存儲在EG(This),一種是當前作用域狀態,以this變量存儲在EG(active_symbol_table)(當前執行環境的活動符號表)。
在我們執行一個 op_array 時,比如一個對象的方法,PHP內核會給這個 op_array 生成一個 zendexecutedata ,在生成初始化時,EG(This) 會添加到EG(active_symbol_table) 。
在方法調用過程中,如果有用到this變量,則會直接取EG(active_symbol_table)的值。
那麼一個對象中的EG(This)在哪裡初始化呢?
就EG(This)變量本身來說,在我們初始化PHP的執行環境時,它和其它全局變量(如EG(scope)等)一樣都會被初始化為NULL。
對於一個對象來說,當我們創建了一個對象,調用時,PHP內核會將當前獲得的對象直接賦值給EG(This),而這個當前獲得的對象是在通過new操作生成對象時創建的對象本身。
如下這個簡單示例:
代碼如下 復制代碼 class Foo {其主程序流程生成的中間代碼如下:
代碼如下 復制代碼 function name: (null)變量原始的對象值出生在 opcode NEW,經過了賦值(ASSIGN)後,在方法初始化時,將變量本身傳遞給執行環境的調用者,調用者又在執行調用(DO_FCALL_BY_NAME)時將變量傳遞給EG(This),當執行這個方法的op_array時,初始化當前作用域的環境(zend_execute_data)時,會將EG(This)作為$this變量添加到活動符號表,後續方法中的$this變量的使用就會直接取符號表的變量。