摘要:但是到底是如何找到對(duì)應(yīng)的函數(shù)的呢今天,我們來(lái)一起尋找答案函數(shù)分類首先,我們先回顧一下的函數(shù)分類,函數(shù)包含用戶自定義函數(shù)內(nèi)部函數(shù)匿名函數(shù)等多種類型。用戶自定義函數(shù)和內(nèi)部函數(shù)編譯完成后會(huì)將函數(shù)名注冊(cè)到全局函數(shù)列表中。
對(duì)于PHPer而言,我們通常會(huì)把常用的功能封裝成一個(gè)函數(shù)來(lái)進(jìn)行復(fù)用,以提升開(kāi)發(fā)效率。但是php到底是如何找到對(duì)應(yīng)的函數(shù)的呢?今天,我們來(lái)一起尋找答案~函數(shù)分類
首先,我們先回顧一下php的函數(shù)分類,php函數(shù)包含用戶自定義函數(shù)、內(nèi)部函數(shù)、匿名函數(shù)等多種類型。而對(duì)于用戶自定義函數(shù)和內(nèi)部函數(shù),他們分別存在對(duì)應(yīng)自己的數(shù)據(jù)結(jié)構(gòu),但是Zend引擎為了適配兩種函數(shù)類型,所以定義了一種新的數(shù)據(jù)結(jié)構(gòu):zend_function聯(lián)合體
數(shù)據(jù)結(jié)構(gòu)我們還是先看下zend_function聯(lián)合體,了解下為什么針對(duì)用戶自定義函數(shù)和內(nèi)部函數(shù)要做適配
typedef union _zend_function { zend_uchar type; //函數(shù)類型,用來(lái)標(biāo)記是用戶自定義函數(shù)還是內(nèi)部函數(shù) struct { zend_uchar type; /* never used */ char *function_name; //函數(shù)名稱 zend_class_entry *scope; //函數(shù)所在的類作用域,用來(lái)標(biāo)記作為成員方法時(shí)所屬的類 zend_uint fn_flags; // 標(biāo)記其作為類的成員方法時(shí)的訪問(wèn)類型,是public、protected還是private union _zend_function *prototype; //函數(shù)原型,標(biāo)記內(nèi)部函數(shù)或者用戶自定義函數(shù)所屬的zend_function zend_uint num_args; //函數(shù)的參數(shù)數(shù)量 zend_uint required_num_args; //必傳的參數(shù)數(shù)量 zend_arg_info *arg_info; //參數(shù)信息指針 zend_bool pass_rest_by_reference; unsigned char return_reference; //返回值 } common; zend_op_array op_array; //用戶自定義函數(shù)結(jié)構(gòu)體 zend_internal_function internal_function; //內(nèi)部函數(shù)結(jié)構(gòu)體 } zend_function; struct _zend_op_array { /* 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; unsigned char return_reference; /* END of common elements */ zend_bool done_pass_two; ....// 其它字段 } 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; unsigned char return_reference; /* END of common elements */ void (*handler)(INTERNAL_FUNCTION_PARAMETERS); struct _zend_module_entry *module; } zend_internal_function;
從上面介紹的內(nèi)容,我們可以發(fā)現(xiàn),不管是用戶自定義函數(shù)還是內(nèi)部函數(shù),在底層存儲(chǔ)時(shí)都會(huì)存在共有字段type和common,所以他們以聯(lián)合體的方式共享內(nèi)存,可以節(jié)省內(nèi)存空間和快速獲取函數(shù)的基本信息,并且如果有需要,可以在一些結(jié)構(gòu)間完美的進(jìn)行強(qiáng)制類型轉(zhuǎn)換。即zend_function可以與zend_op_array互換,zend_function可以與zend_internal_function互換
函數(shù)注冊(cè)聊完了用戶自定義函數(shù)和內(nèi)部函數(shù)的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ),我們?cè)賮?lái)看下全局函數(shù)列表
全局函數(shù)列表,可以理解成函數(shù)注冊(cè)表,其內(nèi)部實(shí)現(xiàn)是一個(gè)哈希表。用戶自定義函數(shù)和內(nèi)部函數(shù)編譯完成后會(huì)將函數(shù)名注冊(cè)到全局函數(shù)列表中。也就是此時(shí)會(huì)判斷是否全局函數(shù)列表中存在同名函數(shù)
那么用戶自定義函數(shù)和內(nèi)部函數(shù)在存儲(chǔ)到全局函數(shù)列表時(shí)有什么不同呢?
用戶自定義函數(shù):
我們寫(xiě)的php函數(shù)在編譯階段會(huì)經(jīng)過(guò)詞法分析->語(yǔ)法分析->生成中間代碼opcode->執(zhí)行中間代碼的過(guò)程,執(zhí)行中間代碼時(shí),會(huì)將函數(shù)名注冊(cè)到全局函數(shù)列表
內(nèi)部函數(shù):
php啟動(dòng)時(shí),會(huì)加載所有擴(kuò)展模塊,并為擴(kuò)展模塊中每一個(gè)函數(shù)創(chuàng)建一個(gè)zend_internal_function結(jié)構(gòu),并將這個(gè)函數(shù)名注冊(cè)到全局函數(shù)列表
接下來(lái),我們?cè)賮?lái)看下調(diào)用函數(shù)時(shí),是如何執(zhí)行的呢?
函數(shù)調(diào)用時(shí),首先會(huì)根據(jù)函數(shù)名去全局函數(shù)列表內(nèi)查找是否存在該函數(shù),如果不存在,則會(huì)直接報(bào)出“Call to undefined function xxx()"的錯(cuò)誤信息;如果存在,則獲取該函數(shù)指針對(duì)應(yīng)的函數(shù)結(jié)構(gòu)中的type字段,判斷其函數(shù)類型,如果函數(shù)類型是自定義函數(shù),則調(diào)用zend_execute來(lái)執(zhí)行函數(shù)的zend_op_array內(nèi)容,而如果函數(shù)類型是內(nèi)部函數(shù),則直接調(diào)用zend_internal_function的handle指針指向的擴(kuò)展模塊的C函數(shù)
總結(jié)到這里,大家應(yīng)該可以找到開(kāi)頭我們提出的問(wèn)題的答案了。其實(shí)就是通過(guò)函數(shù)注冊(cè)到全局函數(shù)列表,然后函數(shù)調(diào)用時(shí),再?gòu)娜趾瘮?shù)列表中查找對(duì)應(yīng)函數(shù)進(jìn)行執(zhí)行來(lái)實(shí)現(xiàn)的;只不過(guò),對(duì)于用戶自定義函數(shù)和內(nèi)部函數(shù)而言,其實(shí)現(xiàn)方式不同,當(dāng)然這也就意味著執(zhí)行效率的不同(當(dāng)然php內(nèi)部函數(shù)執(zhí)行效率更高了,因?yàn)樗鼪](méi)有運(yùn)行時(shí)的編譯階段,相當(dāng)于直接執(zhí)行c語(yǔ)言,所以能用php內(nèi)部函數(shù)的盡量使用內(nèi)部函數(shù))
今天我們就聊到這里了,歡迎大家的手動(dòng)點(diǎn)贊~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/31237.html
摘要:對(duì)于來(lái)說(shuō),變量有全局變量和局部變量之分那么,他們都是存儲(chǔ)到一個(gè)哈希表內(nèi)了么其實(shí)不是的,變量存儲(chǔ)也有作用域的概念。 上次跟大家講了垃圾回收機(jī)制后,有些小伙伴對(duì)底層原理比較感興趣,私信問(wèn)我了一些關(guān)于變量的相關(guān)知識(shí),既然大家對(duì)變量比較感興趣,那么這次我們來(lái)系統(tǒng)的講一下變量的底層原理 變量結(jié)構(gòu) 首先,我們還是先擺上我們的zval結(jié)構(gòu)體,即php所有變量都會(huì)以zval結(jié)構(gòu)體的形式實(shí)現(xiàn) struc...
摘要:數(shù)組是最常用的數(shù)據(jù)類型,同時(shí)容易上手也得益于其強(qiáng)大的數(shù)組,但是數(shù)組在中是如何實(shí)現(xiàn)的呢首先,我們還是先了解下相關(guān)的數(shù)據(jù)結(jié)構(gòu),為下面的內(nèi)容打好基礎(chǔ)哈希表哈希表,顧名思義,即將不同的關(guān)鍵字映射到不同單元的一種數(shù)據(jù)結(jié)構(gòu)。 數(shù)組是PHPer最常用的數(shù)據(jù)類型,同時(shí)php容易上手也得益于其強(qiáng)大的數(shù)組,但是數(shù)組在php中是如何實(shí)現(xiàn)的呢? 首先,我們還是先了解下相關(guān)的數(shù)據(jù)結(jié)構(gòu),為下面的內(nèi)容打好基礎(chǔ) 哈希...
摘要:但是對(duì)于結(jié)構(gòu)體中的和字段我們一直都沒(méi)有詳細(xì)介紹過(guò),而這兩個(gè)字段其實(shí)是和變量之間賦值的原理有著密切的關(guān)系的。 上周我們從底層的角度介紹了php變量從生成->常量賦值->銷毀的完整生命周期(不了解的同學(xué)可以翻看一下前面的文章php底層原理之變量(一)),但是我們留了一個(gè)思考,不知道大家有答案了沒(méi),變量之間的賦值在底層又是如何實(shí)現(xiàn)的呢? 變量之間賦值 php變量的zval結(jié)構(gòu),我們已經(jīng)介紹了...
摘要:總結(jié)垃圾回收機(jī)制以的引用計(jì)數(shù)機(jī)制為基礎(chǔ)以前只有該機(jī)制同時(shí)使用根緩沖區(qū)機(jī)制,當(dāng)發(fā)現(xiàn)有存在循環(huán)引用的時(shí),就會(huì)把其投入到根緩沖區(qū),當(dāng)根緩沖區(qū)達(dá)到配置文件中的指定數(shù)量后,就會(huì)進(jìn)行垃圾回收,以此解決循環(huán)引用導(dǎo)致的內(nèi)存泄漏問(wèn)題開(kāi)始引入該機(jī)制 php垃圾回收機(jī)制,對(duì)于PHPer來(lái)說(shuō)是一個(gè)不陌生但是又不是很熟悉的內(nèi)容。那么php是怎么實(shí)現(xiàn)對(duì)不需要的內(nèi)存進(jìn)行回收的呢? php變量的內(nèi)部存儲(chǔ)結(jié)構(gòu) 首先還是...
摘要:那些瑣碎的知識(shí)點(diǎn)作者記錄的的很奇特很難記的知識(shí)點(diǎn)。易錯(cuò)知識(shí)點(diǎn)整理注意和的區(qū)別中和都是輸出的作用,但是兩者之間還是有細(xì)微的差別。今天手頭不忙,總結(jié)一下,分享過(guò)程中掌握的知識(shí)點(diǎn)。 深入理解 PHP 之:Nginx 與 FPM 的工作機(jī)制 這篇文章從 Nginx 與 FPM 的工作機(jī)制出發(fā),探討配置背后的原理,讓我們真正理解 Nginx 與 PHP 是如何協(xié)同工作的。 PHP 那些瑣碎的知識(shí)...
閱讀 2201·2021-11-22 11:56
閱讀 2647·2021-10-08 10:05
閱讀 7772·2021-09-22 15:53
閱讀 1910·2021-09-22 15:29
閱讀 2234·2021-09-08 09:35
閱讀 3354·2021-09-07 10:12
閱讀 1379·2019-08-30 13:11
閱讀 1968·2019-08-28 17:54