1. 程式人生 > 其它 >從零開始寫 PHP 擴充套件

從零開始寫 PHP 擴充套件

PHP 是用 C 語言寫的。對於每個 PHPer 來說,都有著內心的一種希望寫擴充套件的衝動了吧。然而,缺乏一個很好的切入點。Google 上搜 PHP 擴充套件開發,大部分都是複製品文章,甚至有些人連操作都沒有操作過就搬運在了自己的部落格。不過也有幾篇好教程,但是都是 PHP 5 時代的產物,隱藏著非常多的坑。我會將我自己慢慢踩坑的過程記錄下來,也許這就成了其它人的“教程”了吧。

生成一個擴充套件

想必很多人已經看到很多網上的教程了。大多都是教我們執行這個命令: $./ext_skel--extname=extname。但是,當你 clone 了 PHP 原始碼後會發現,master 分支下並沒有 ext/ext_skel

這個檔案。所以,我總結了一下:

如果你是直接下載 PHP 的原始碼,或者在已經 release 的版本分之下,你可以執行這個命令

$ cd ext
$ ./ext_skel --extname=extname

如果你是直接在 master 分支下,只有 ext_skel.php 檔案,這個時候你就直接可以執行這個 PHP 檔案

$ cd ext
$ php ext_skel.php --ext extname

由於我是直接在 master 分支下開發的,所以後面的都是預設在 master 分之下的操作。

生成了擴充套件之後,我們會看到四個檔案和一個資料夾。現在這個階段,我們只需要用到兩個檔案, .c

檔案和 .h 檔案。

一個小坑

在我們生成好擴充套件之後,我們可以試著編譯一下

$ phpize
$ ./configure
$ make && make test

我們會驚訝地發現,編譯的時候會有一個 warning。

warning: implicit declaration of function
      'ZEND_PARSE_PARAMETERS_NONE' is invalid in C99 [-Wimplicit-function-declaration]
        ZEND_PARSE_PARAMETERS_NONE();
        ^
1 warning generated.

然後你再執行 make test 發現有一個測試沒有通過。沒錯,指令碼為我們生成好的檔案,居然通不過自己的測試。有沒有覺得很詭異。我們看看 warning 的具體資訊。找不到函式 ZEND_PARSE_PARAMETERS_NONE。看了一下檔案,發現在第 15 行。看看這個函式名大概也能猜出來是什麼意思了。於是我去 PHP 原始碼裡搜了一下。可是我們發現了這樣一個巨集定義。

#ifndef zend_parse_parameters_none
#define zend_parse_parameters_none()    
        zend_parse_parameters(ZEND_NUM_ARGS(), "")
#endif

替換掉原來的大寫之後,就沒有 warning 了。這也算是官方給我們挖了一個小坑吧。雖然大寫的有巨集定義,但是為什麼會報錯,我也不太清楚了。

定義一個函式

我想,大多數人寫擴充套件,肯定至少希望實現一個函式,不會是要幾個全域性變數就去寫個擴充套件的吧(霧

這裡 PHP 給我們提供了一個有用的巨集 PHP_FUNCTION。生成好的程式碼裡也有定義好的兩個函式,可以參照它的用法。這個巨集最終會被翻譯成一個函式。例如 PHP_FUNCTION(name) 最終會被翻譯成 voidzif_name(zend_execute_data*execute_data,zval*return_value)

同時我們看到有定義了這麼一個數組

const zend_function_entry cesium_functions[] = {
    PHP_FE(cesium_test1,        arginfo_cesium_test1)
    PHP_FE(cesium_test2,        arginfo_cesium_test2)
    PHP_FE_END
};

我們需要將新新增的函式新增到這個數組裡。像這樣

const zend_function_entry cesium_functions[] = {
    PHP_FE(cesium_test1,        arginfo_cesium_test1)
    PHP_FE(cesium_test2,        arginfo_cesium_test2)
    PHP_FE(name,           NULL)
    PHP_FE_END
};

記住,結尾不要加分號或者逗號。最後,我們可以個這個函式一個輸出

PHP_FUNCTION(name)
{
    php_printf("Hellon");
}

編譯安裝完了之後我們就可以使用這個函數了

總結

本文僅僅是展示了從建立擴充套件開始到執行的全過程,本著能執行的心態來走完這些流程。

由於作者水平有限,如有錯誤,敬請不吝賜教。

覺得本文對你有幫助?請分享給更多人。