1.函數的存儲結構
typedef union _zend_function zend_function;
union _zend_function {
zend_uchar type;
struct {
zend_uchar type;
zend_uchar arg_flags[3];
uint32_t fn_flags;
zend_string *function_name;
zend_class_entry *scope; //成員方法所屬類,面向對象實作中用到
union _zend_function *prototype;
uint32_t num_args; //參數數量
uint32_t required_num_args; //必傳參數數量
zend_arg_info *arg_info; //參數資訊
} common;
zend_op_array op_array; //自定義函數(函數實際編譯為普通的zend_op_array)
zend_internal_function internal_function; //内部函數(通過擴充或者核心提供的C函數)
};
zend_function.common.xx快速通路到zend_function.zend_op_array.xx及zend_function.zend_internal_function.xx
zend_function.type取到zend_function.op_array.type及zend_function.internal_function.type

PHP在編譯階段将使用者自定義的函數編譯為獨立的opcodes,儲存在EG(function_table)中,調用時重新配置設定新的zend_execute_data(相當于運作棧),然後執行函數的opcodes,調用完再還原到舊的zend_execute_data,繼續執行,EG(function_table)是一個哈希表,記錄的就是PHP中所有的函數
2.函數參數
函數參數在核心實作上與函數内的局部變量實際是一樣的,提供一個單獨的編号,參數名稱也在zend_op_array.vars中,編号首先是從參數開始的,是以按照參數順序其編号依次為0、1、2...(轉化為相對記憶體偏移量就是96、112、128...),然後函數調用時首先會在調用位置将參數的value複制到各參數各自的位置
//參數的額外資訊
typedef struct _zend_arg_info {
zend_string *name; //參數名
zend_string *class_name;
zend_uchar type_hint; //顯式聲明的參數類型,比如(array $param_1)
zend_uchar pass_by_reference; //是否引用傳參,參數前加&的這個值就是1
zend_bool allow_null; //是否允許為NULL
zend_bool is_variadic; //是否為可變參數,即...用法,function my_func($a, ...$b){...}
} zend_arg_info;
每個參數都有一個上面的結構,所有參數的結構儲存在zend_op_array.arg_info數組中,這裡有一個地方需要注意:zend_op_array->arg_info數組儲存的并不全是輸入參數,如果函數聲明了傳回值類型則也會為它建立一個zend_arg_info,這個結構在arg_info數組的第一個位置,這種情況下zend_op_array->arg_info指向的實際是數組的第二個位置,傳回值的結構通過zend_op_array->arg_info[-1]讀取
3.内部函數
内部函數指的是由核心、擴充提供的C語言編寫的function,這類函數不需要經曆opcode的編譯過程,是以效率上要高于PHP使用者自定義的函數,調用時與普通的C程式沒有差異。Zend引擎中定義了很多内部函數供使用者在PHP中使用,比如:define、defined、strlen、method_exists、class_exists、function_exists......等等,除了Zend引擎中定義的内部函數,PHP擴充中也提供了大量内部函數,我們也可以靈活的通過擴充自行定制。
//zend_internal_function頭部是一個與zend_op_array完全相同的common結構
typedef struct _zend_internal_function {
/* Common elements */
zend_uchar type;
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
uint32_t fn_flags;
zend_string* function_name;
zend_class_entry *scope;
zend_function *prototype;
uint32_t num_args;
uint32_t required_num_args;
zend_internal_arg_info *arg_info;
/* END of common elements */
void (*handler)(INTERNAL_FUNCTION_PARAMETERS); //函數指針,展開:void (*handler)(zend_execute_data *execute_data, zval *return_value)
struct _zend_module_entry *module;
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
} zend_internal_function;