摘要:語言中的宏,我認為,可以理解為一種簡單的封裝。通過宏定義,可以對開發者隱去一些細節,讓開發者在使用簡單的語法來完成重復的復雜的編碼。當然,宏定義還有其它的用途,但是,我們在涉及到的就是這個作用。我們看到,在宏定義中,使用了另外的宏。
PHP 的函數本人也只是個初入門的菜鳥,因對技術有著向往,故在“無趣”的工作之余,盡自己所能提升自己。由于我的 C 語言功底也有限,故本文的深度也有限,如有幸得大牛閱讀,還望指導一二,小弟感激不盡。
作為 PHPer,我們幾乎每天都在寫函數,我們一定會好奇,那些 PHP 內置的函數,是長什么樣子的。如果寫過 PHP 擴展的話,一定知道這個宏:PHP_FUNCTION。在定義一個函數的時候,這樣來使用這個宏。例如 array_change_key_case,它的定義是這樣的:PHP_FUNCTION(array_change_key_case)。沒錯,就是這么簡單。但是,在這個簡單的背后,卻沒有這么簡單。
PHP_FUNCTION 追根溯源 宏相信對這篇文章感興趣的同學,一定多少對 C 語言以及它的宏定義有一定的了解。如果沒有,也不要緊,我這里來簡單解釋一下,什么是宏。
C 語言中的宏,我認為,可以理解為一種簡單的封裝。通過宏定義,可以對開發者隱去一些細節,讓開發者在使用簡單的語法來完成重復的復雜的編碼。當然,宏定義還有其它的用途,但是,我們在 PHP_FUNCTION 涉及到的就是這個作用。有下面的代碼。
#define TEST(test) void test(int a) TEST(haha)
宏,就是完全的替換,即使用后面的語句替換前面的。那么對于下面的 TEST(haha) 就相當于下面的樣子。
void haha(int a)PHP_FUNCTION 的定義
首先,我們要定義函數,這樣使用這個宏。
PHP_FUNCTION(array_change_key_case) { // TODO }
我們在 php-src/main/php.h 中找到了下面的定義。
#define PHP_FUNCTION ZEND_FUNCTION
也就是說,這里用 ZEND_FUNCTION 替換了 PHP_FUNCTION 這個宏。所以,我們的定義就相當于變成了這樣。
ZEND_FUNCTION(array_change_key_case) { // TODO }
我們繼續往下找,因為,這里還是宏,我們并沒有看到我們希望看到的代碼。我們可以在 php-src/Zend/zend_API.h 中找到下面的定義。
#define ZEND_FN(name) zif_##name #define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name)) #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
我們看到,在宏定義中,使用了另外的宏。不要怕,還是一個詞,替換。我們按照這樣的步驟來。(## 是一個連接符,它的作用是,是將它前面的與后面的,按照字符串的方式連接起來。
替換 ZEND_FUNCTION
ZEND_NAMED_FUNCTION(ZEND_FN(name)) { // TODO }
替換 ZEND_FN
ZEND_NAMED_FUNCTION(zif_array_change_key_case) { // TODO }
替換 ZEND_NAMED_FUNCTION
void zif_array_change_key_case(INTERNAL_FUNCTION_PARAMETERS) { // TODO }
到這里,我們可以看到,這里已經基本和我們熟悉的函數定義差不多了,不過,這還沒完,以為,這里還有宏,那就是 INTERNAL_FUNCTION_PARAMETERS。我們找到 php-src/Zend/zend.h,可以找到 INTERNAL_FUNCTION_PARAMETERS 的宏定義。
#define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value
好了,依然按照替換的原則,我們就可以將函數定義變成這樣了。
void zif_array_change_key_case(zend_execute_data *execute_data, zval *return_value) { // TODO }
看,整個函數的定義,已經完全沒有宏了,這已經是我們在熟悉不過的 C 語言函數的定義了。這就是
PHP_FUNCTION 的整個定義的過程。
return_value,顧名思義,就是定義的 PHP 函數的返回值。而 execute_data,按照我的理解,就是 Zend 內部的一個調用棧,而在執行這個函數的時候,指向的是這個函數的棧幀。具體的細節,暫時在這里先不考慮,有興趣的同學可以來這里看一下。深入理解 PHP 內核
后記我始終認為,對于一個 PHPer 來說,C 語言是一項必不可少的技能。理解 PHP 的內核,對于我們編寫出高質量的代碼,起到了關鍵的作用。所以,我現在開始研究 PHP 的源碼實現了。我希望我能通過這些文章,記錄下我理解源碼的瞬間,也希望我的文章能讓更多的 PHPer,進入到 PHP 內核的世界。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/25592.html
摘要:關于宏熟悉擴展開發的同學應該都知道,這個宏,是定義一個函數用的,參數就是函數的函數名。關于這個宏,有興趣的可以去看看源碼,它其實是將替換成了,這樣的一個函數定義。上面的幾個宏,是為了檢查并獲取傳參進函數的變量。 因為已經有文檔了,可能有些人覺得我寫這個有些多余了。可是并不是每一個 PHPer 都會好好地去閱讀文檔,自然有一些函數可能都沒有聽說過(很不幸我也是這其中的一員)。我也希望能通...
摘要:我的博客運行以下代碼互聯網產品我們可能以為會得到的結果是互聯網產品,實際結果是互聯網產。所以在執行的時候,通過字節比對,會將去掉,導致了最后出現了亂碼。 我的博客 https://mengkang.net/1039.html 運行以下代碼: $tag = 互聯網產品、; $text = rtrim($tag, 、); print_r($text); 我們可能以為會得到的結果是互聯網產品...
摘要:編譯工具這個腳本主要生成了編譯需要的配置以及擴展的基本結構這個腳本主要是獲取的安裝信息用于生成文件編寫擴展的基本步驟通過目錄下腳本生成擴展的基本框架修改配置設置編譯配置參數設置擴展的源文件依賴庫函數檢查等等定義一個這樣的編譯參數 1. 編譯工具 (a).ext_skel:這個腳本主要生成了編譯需要的配置以及擴展的基本結構 (b).php-config:這個腳本主要是獲取PHP的安裝信息...
摘要:文章來自原文歡迎來到給開發者的源碼系列的第二部分。是在內部代表任意一個變量的定義。這種情況下函數會拋出警告,而此函數馬上返回會返回給的用戶層代碼。原因是,是少數通過而不是擴展定義的函數。下一部分下一部分會再次發表在。 文章來自:http://www.hoohack.me/2016/02/10/understanding-phps-internal-function-definitio...
閱讀 3195·2023-04-26 01:39
閱讀 3349·2023-04-25 18:09
閱讀 1617·2021-10-08 10:05
閱讀 3233·2021-09-22 15:45
閱讀 2775·2019-08-30 15:55
閱讀 2397·2019-08-30 15:54
閱讀 3170·2019-08-30 15:53
閱讀 1328·2019-08-29 12:32