日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

php内核函数手册,深入理解PHP内核(五)函数的内部结构,深入理解内部结构

發(fā)布時(shí)間:2025/3/21 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php内核函数手册,深入理解PHP内核(五)函数的内部结构,深入理解内部结构 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

深入理解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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。