php内核函数手册,深入理解PHP内核(五)函数的内部结构,深入理解内部结构
深入理解PHP內核(五)函數的內部結構,深入理解內部結構
php的函數包括用戶定義的函數、內部函數(print_r count...)、匿名函數、變量函數($func = 'print_r'; $func(array('a','b'));)
PHP內核源碼中將函數分為以下類型
#define ZEND_INTERNAL_FUNCTION 1
#define ZEND_USER_FUNCTION 2
#define ZEND_OVERLOADED_FUNCTION 3
#define ZEND_EVAL_CODE 4
#define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
一、用戶函數(ZEND_USER_FUNCTION)
函數不一定顯式的有返回值,在PHP的實現中即使沒有顯式的返回,PHP內核也會幫我們返回NULL。
ZEND在執行過程中,會將運行時信息存儲于_zend_execute_data中:
struct_zend_execute_data {//...省略部分代碼
zend_function_state function_state;
zend_function*fbc; /*Function Being Called*/
//...省略部分代碼
};
在程序初始化的過程中,function_state也會進行初始化,function_state由兩個部分組成:
typedef struct_zend_function_state {
zend_function*function;void **arguments;
} zend_function_state;
*arguments是一個指向函數參數的指針,而函數體本事存儲于*function中,*function是一個zend_function結構體,它最終存儲了用戶自定義函數的一切信息,具體結構如下:
typedef union _zend_function {
zend_uchar type;/*MUST be the first element of this struct!*/
struct{
zend_uchar type;/*never used*/
char *function_name; //函數名稱
zend_class_entry *scope; //函數所在的類作用域
zend_uint fn_flags; //函數類型,如用戶自定義則為 #define
ZEND_USER_FUNCTION 2union _zend_function*prototype; //函數原型
zend_uint num_args; //參數數目
zend_uint required_num_args; //需要的參數數目
zend_arg_info *arg_info; //參數信息指針
zend_bool pass_rest_by_reference;
unsignedchar return_reference; //返回值
} common;
zend_op_array op_array;//函數中的操作
zend_internal_function internal_function;
} zend_function;
zend_function的結構體中的op_array存儲了該函數中的所有操作,當函數被調用時,ZEND就會將這個op_array中的opline一條條順序執行,并將最后的結果返回。函數的定義和執行是分開的,一個函數可以作為一個獨立的運行單元存在。
二、內部函數(ZEND_INTERNAL_FUNCTION)
ZEND_INTERNAL_FUNCTION函數是由擴展或者Zend/PHP內核提供的,用c/c++編寫,可以直接執行的函數,以下為內部函數的結構
typedef struct_zend_internal_function {/*Common elements*/zend_uchar type;char *function_name;
zend_class_entry*scope;
zend_uint fn_flags;
union _zend_function*prototype;
zend_uint num_args;
zend_uint required_num_args;
zend_arg_info*arg_info;
zend_bool pass_rest_by_reference;
unsignedcharreturn_reference;/*END of common elements*/
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);struct _zend_module_entry *module;
} zend_internal_function;
在模塊初始化的時候,ZE會遍歷每個載入的擴展模塊,然后將模塊中function_entry中指明的每一個函數(module->functions),創建一個zend_internal_function結構,并將其type設置為ZEND_INTERNAL_FUNCTION,將這個結構填入全局的函數表(HashTable結構);函數設置及注冊過程見Zend/zene_API.c文件中的zend_register_function函數,這個函數除了處理函數頁也處理類的方法,包括那些魔術方法。
內部函數的結構與用戶自定義函數結構基本類似,有一些不同:
調用方法,handler字段,如果是ZEND_INTERNAL_FUNCTION,那么ZEND就會調用zend_execute_internal,通過zend_internal_function.handler來執行這個函數。而用戶自定義函數需要生成中間代碼,然后通過中間代碼映射到相對就把方法調用。
內置函數在結構中多了一個module字段,表示屬于哪個模塊。不同的擴展模塊不同
type字段,在用戶自定義函數中,type字段幾乎無用,而內置函數中的type字段作為幾種內部函數的區分。
三、變量函數
如果一個變量名后邊有圓括號,php將尋找與變量的值同名的函數,并且嘗試執行。
變量函數$func
$func = 'print_r';
$func('i am print_r function.');
編譯后中間代碼
function name: (null)
number of ops:9compiled vars:!0 =$func
line #* op fetch ext returnoperands------------------------------------------------------------------------------
-
-
2 0 >EXT_STMT1 ASSIGN !0,'print_r'
3 2EXT_STMT3 INIT_FCALL_BY_NAME !0
4EXT_FCALL_BEGIN5SEND_VAL'i+am+print_r+function.'
6 DO_FCALL_BY_NAME 1
7EXT_FCALL_END8 > RETURN 1
內部函數
print_r('i am print_r function.');
編譯后中間代碼
function name: (null)
number of ops:6compiled vars: none
line #* op fetch ext returnoperands-------------------------------------------------------------------------------
-
-
2 0 >EXT_STMT1EXT_FCALL_BEGIN2SEND_VAL'i+am+print_r+function.'
3 DO_FCALL 1
'print_r'
4EXT_FCALL_END5 > RETURN 1
對比發現,二者在調用中間代碼上存在一些區別,變量函數是DO_FCALL_BY_NAME,而內部函數是DO_FCALL。這在語法解析時就已經決定了,見Zend/zend_complie.c文件的zend_do_end_function_call函數中部分代碼:
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
opline->opcode =ZEND_DO_FCALL;
opline->op1 = *function_name;
ZVAL_LONG(&opline->op2.u.constant,
zend_hash_func(Z_STRVAL(function_name->u.constant), Z_STRLEN(function_name-
>u.constant) + 1));
}else{
opline->opcode =ZEND_DO_FCALL_BY_NAME;
SET_UNUSED(opline->op1);
}
如果不是方法,并且不是動態調用,并且函數名為字符串變量,則其生成的中間代碼為ZEND_DO_FCALL。其他情況則為ZEND_DO_FCALL_BY_NAME。另外將變量函數作為回調函數,其處理過程在Zend/zend_complie.c文件的zend_do_pass_param函數中,最終會體現在中間代碼執行過程中的ZEND_SEND_VAL_SPEC_CONST_HADNLER等函數中。
四、匿名函數
匿名函數是一類不需要指定表示符,而又可以被調用的函數或子例程,匿名函數可以方便的作為參數傳遞給其他函數。
相關標簽:php
本文原創發布php中文網,轉載請注明出處,感謝您的尊重!
總結
以上是生活随笔為你收集整理的php内核函数手册,深入理解PHP内核(五)函数的内部结构,深入理解内部结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 函数静态变量,php 函数中静态
- 下一篇: 2018年4月java自考真题,全国20