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