php 內核探祕之 PHP_FUNCTION 宏

本人也只是個初入門的菜鳥,因對技術有着嚮往,故在「無趣」的工做之餘,盡本身所能提高本身。因爲個人 C 語言功底也有限,故本文的深度也有限,若有幸得大牛閱讀,還望指導一二,小弟感激涕零。php

PHP 的函數

做爲 PHPer,咱們幾乎天天都在寫函數,咱們必定會好奇,那些 PHP 內置的函數,是長什麼樣子的。若是寫過 PHP 擴展的話,必定知道這個宏:PHP_FUNCTION。在定義一個函數的時候,這樣來使用這個宏。例如 array_change_key_case,它的定義是這樣的:PHP_FUNCTION(array_change_key_case)。沒錯,就是這麼簡單。可是,在這個簡單的背後,卻沒有這麼簡單。函數

PHP_FUNCTION 追根溯源

相信對這篇文章感興趣的同窗,必定多少對 C 語言以及它的宏定義有必定的瞭解。若是沒有,也沒關係,我這裏來簡單解釋一下,什麼是宏。編碼

C 語言中的宏,我認爲,能夠理解爲一種簡單的封裝。經過宏定義,能夠對開發者隱去一些細節,讓開發者在使用簡單的語法來完成重複的複雜的編碼。固然,宏定義還有其它的用途,可是,咱們在 PHP_FUNCTION 涉及到的就是這個做用。有下面的代碼。code

#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 中找到了下面的定義。get

#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)

咱們看到,在宏定義中,使用了另外的宏。不要怕,仍是一個詞,替換。咱們按照這樣的步驟來。(## 是一個鏈接符,它的做用是,是將它前面的與後面的,按照字符串的方式鏈接起來。class

  1. 替換 ZEND_FUNCTION

ZEND_NAMED_FUNCTION(ZEND_FN(name))
{
    // TODO
}
  1. 替換 ZEND_FN

ZEND_NAMED_FUNCTION(zif_array_change_key_case)
{
    // TODO
}
  1. 替換 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 的整個定義的過程。

execute_data 和 return_value

return_value,顧名思義,就是定義的 PHP 函數的返回值。而 execute_data,按照個人理解,就是 Zend 內部的一個調用棧,而在執行這個函數的時候,指向的是這個函數的棧幀。具體的細節,暫時在這裏先不考慮,有興趣的同窗能夠來這裏看一下。深刻理解 PHP 內核

後記

我始終認爲,對於一個 PHPer 來講,C 語言是一項必不可少的技能。理解 PHP 的內核,對於咱們編寫出高質量的代碼,起到了關鍵的做用。因此,我如今開始研究 PHP 的源碼實現了。我但願我能經過這些文章,記錄下我理解源碼的瞬間,也但願個人文章能讓更多的 PHPer,進入到 PHP 內核的世界。

相關文章
相關標籤/搜索