函式的定義是乙個將函式名註冊到函式列表的過程
1. 詞法分析:
function將會生成t_function標記
2. 語法分析:
3. 生成中間**:
生成的中間**為 zend_declare_function ,根據這個中間**及運算元對應的op_type。 我們可以找到中間**的執行函式為 zend_declare_function_spec_handler。
在生成中間**時,已經統一了函式名全部為小寫,表示函式的名稱不是區分大小寫的。
4. 執行中間**:
執行函式呼叫函式do_bind_function,在這個函式中將ex(opline)所指向的函式新增到eg(function_table)中,並判斷是否已經存在相同名字的函式,如果存在則報錯。 eg(function_table)用來存放執行過程中全部的函式資訊,相當於函式的登錄檔。
使用者自定義函式的引數
在經過詞語分析,語法分析後,我們知道對於函式的引數檢查是通過 zend_do_receive_arg 函式來實現的。
整個引數的傳遞是通過給中間**的arg_info欄位執行賦值操作完成。
eg(current_execute_data)。這個變數存放的是當前執行程式或函式的資料。此時我們需要取前乙個執行程式的資料,為什麼呢? 因為這個函式的呼叫是在進入函式後執行的
引數的傳遞
每個php指令碼都有自己專屬的全域性符號表,而每個使用者自定義的函式也有自己的符號表, 這個符號表用來儲存在這個函式作用域下的屬於它自己的變數。當呼叫每個使用者自定義的函式時, 都會為這個函式建立乙個符號表,當這個函式返回時都會釋放這個符號表。
當執行乙個擁有引數的使用者自定義的函式時,其實它相當於賦值乙個操作,即s=
a; 只是這個賦值操作的引用計數會執行兩次,除了給函式自定義的符號表,還有乙個是給函式棧。
引數的傳遞的第一步是send_var操作,函式呼叫是do_fcall,在此中間**之前有乙個send_var操作,此操作的作用是將實參傳遞給函式, 並且將它新增到函式棧中。
第二步是recv操作。 recv操作和send_var操作不同,它是歸屬於當前函式的操作,僅為此函式服務。 它的作用是接收send過來的變數,並將它們新增到當前函式的符號表。
引數的壓棧操作使用者自定義的函式和內建函式都需要,而recv操作僅使用者自定義函式需要。
**呼叫**foo的opcode是「do_fcall「, do_fcall進行函式呼叫操作時,ze會在function_table中根據函式名查詢函式的定義;
如果存在,就返回該函式zend_function結構指標, 然後通過function.type的值來判斷函式是內部函式還是使用者定義的函式: 呼叫zend_execute_internal(zend_internal_function.handler)或者直接 呼叫zend_execute來執行這個函式包含的zend_op_array。
執行
那麼,在函式執行的時候, 進入函式前的環境資訊是必須要儲存的。在函式執行完畢後,這些環境資訊也會被還原,使整個程式繼續的執行下去。
內部函式的執行與使用者函式不同。使用者函式是php語句一條條「翻譯」成op_line組成的乙個op_array,而內部函式則是用c來實現的,因為執行環境也是c環境。
內部函式和使用者函式的處理都是由do_fcall來進行的。對於內部函式,zend_execute_internal函式沒有定義的情況下,會進行另外乙個比較長的呼叫。
內部函式所在的結構體中 有乙個handler指標指向此函式需要呼叫的內部定義的c函式。 這些內部函式在模組初始化時就以擴充套件的函式的形式載入到eg(function_table)。
$func = 'print_r';
$func(『i am print_r function.』);
使用create_function()建立」匿名」函式:
<?php
$func = create_function('', 'echo "function created dynamic";');
echo fu
nc;/
/lam
bda1
func(); // function created dynamic my
func
=『la
mbda
′1; my_func(); // 不存在這個函式
lambda_1(); // 不存在這個函式
create_function函式的返回值: 函式返回乙個唯一的字串函式名,出現錯誤的話則返回false。
該函式在定義了乙個函式之後,給函式起了個名字,它將函式名的第乙個字元變為了』\0』也就是空字元, 然後在函式表中查詢是否已經定義了這個函式,如果已經有了則生成新的函式名, 第乙個字元為空字元的定義方式比較特殊, 因為在使用者**中無法定義出這樣的函式, 也就不存在命名衝突的問題了.
__invoke魔幻方法
?php
class callme
}$call = new callme();
$call(13810688888); // "hello: 13810688888
匿名函式的實現
<?php
$func = function()
echo gettype($func); // object
echo get_class($func); // closure
php核心探索 常量
在php中常量的結構只是在變數的基礎上新增了一些額外的元素 typedef struct zend constant zend constant php常量定義方式 define think in php define定義常量過程 類常量定義 此處不做介紹 值型別判斷和處理 c.value val ...
PHP核心探索 變數概述
現代程式語言中的基本元素主要有 變數,流程控制介面,函式等等我能否不使用變數來編寫程式呢?這顯然是可以的,例如 複製 如下 php echo hello andhm 這個程式很簡單,輸出乙個字串內容。就和我們僅僅使用二進位制也能程式設計一樣,不使用變數也能完成大部分的工作,不使用變數我們的程式將喪失...
php核心探索筆記 直譯器的執行過程
以cli sapi為例來對php執行核心部分進行解析。cli是php命令列模式,此sapi是預設安裝的,在伺服器端安裝過php後,生成以乙個可執行檔案,可以在shell中呼叫php命令來執行。php f xx.php執行流程 在第3個階段中,如何執行php指令碼的 通過呼叫php execute s...