實現(xiàn)一個PHP的C擴(kuò)展 [入門篇]

最近想嘗試寫PHP的C擴(kuò)展惶翻,在《PHP7底層設(shè)計與源碼實現(xiàn)》書中有一個PHP擴(kuò)展的例子丁溅,這里動手實現(xiàn)了一下鹦蠕。

準(zhǔn)備

Linux
PHP7
PHP7源碼包 點擊下載

預(yù)覽

Linux查看文本行數(shù)可以使用wc -l查看佑力,現(xiàn)在需要將這一功能實現(xiàn)為PHP的自帶功能筋量。


假如有這樣一個文本,中間有空行拯欧,要分析該文本行數(shù)详囤,有些時候需要讓函數(shù)輸出3,有些時候讓函數(shù)輸出7(包括空行)镐作,可以通過配置php.ini文件保存這一配置藏姐。
然后在PHP中這樣使用就好了:

開始
  1. 首先使用PHP7源碼包中的ext_skel工具生成擴(kuò)展的基本框架,進(jìn)入源碼包目錄執(zhí)行./ext_skel --extname=wcl该贾,之后會在ext_skel同目錄下生成一個wcl文件夾羔杨,其中wcl.c是擴(kuò)展的主要源文件,php_wcl.h是頭文件杨蛋。
  2. 編輯config.m4兜材,去掉PHP_ARG_ENABLE和[--enable-wcl]的注釋dnl,我這邊生成的config.m4默認(rèn)是下面的樣子逞力,就不用改了曙寡。


  3. 編輯wcl.c文件:


/* Every user-visible function in PHP should document itself in the source */
/* {{{ proto string confirm_wcl_compiled(string arg)
   Return a string to confirm that the module is compiled in */
PHP_FUNCTION(wcl)
{
    size_t arg_len, len;

    int argc = ZEND_NUM_ARGS();
    char *arg = NULL;
    if (zend_parse_parameters(argc, "s", &arg, &arg_len) == FAILURE) {
        return;
    }

//  zend_string *strg;
//  strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "wcl", arg);
//  RETURN_STR(strg);

    FILE *fp;
    if ((fp = fopen(arg, "r")) == NULL) {
        RETURN_FALSE;
    }

    char ch, pre = '\n';
    zend_long lcount = 0;
    while ((ch = fgetc(fp)) != EOF) {
        if (ch == '\n') {
            lcount++;
        }
        pre = ch;
    }

    fclose(fp);
    RETURN_LONG(lcount);
}
/* }}} */



/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(wcl)
{
#if defined(COMPILE_DL_WCL) && defined(ZTS)
    ZEND_TSRMLS_CACHE_UPDATE();
#endif
    return SUCCESS;
}
/* }}} */


/* {{{ PHP_MINFO_FUNCTION
這里是執(zhí)行phpinfo()函數(shù)的輸出
 */
PHP_MINFO_FUNCTION(wcl)
{
    php_info_print_table_start();
    php_info_print_table_header(2, "wcl support", "enabled");
    php_info_print_table_end();

    /* Remove comments if you have entries in php.ini
    DISPLAY_INI_ENTRIES();
    */
}
/* }}} */

/* {{{ wcl_functions[]
 *
 * Every user visible function must have an entry in wcl_functions[].
 */
const zend_function_entry wcl_functions[] = {
    PHP_FE(wcl, NULL)       /* 注冊上面定義的wcl函數(shù)*/
    PHP_FE_END  /* Must be the last line in wcl_functions[] */
};
/* }}} */

/* {{{ wcl_module_entry
 */
zend_module_entry wcl_module_entry = {
    STANDARD_MODULE_HEADER,
    "wcl",
    wcl_functions,
    PHP_MINIT(wcl),
    PHP_MSHUTDOWN(wcl),
    PHP_RINIT(wcl),     /* Replace with NULL if there's nothing to do at request start */
    PHP_RSHUTDOWN(wcl), /* Replace with NULL if there's nothing to do at request end */
    PHP_MINFO(wcl),
    PHP_WCL_VERSION,
    STANDARD_MODULE_PROPERTIES
};
/* }}} */

計數(shù)功能主要在wcl函數(shù)中實現(xiàn),無法打開文件返回false寇荧,然后按文件內(nèi)容判斷為換行符管嬉,計數(shù)器+1怯伊,最后返回文件行數(shù)筛婉。

  1. 之前說過對于前面的test.txt(包含多個空行),有時我們需要讓函數(shù)不對空行計數(shù)镀琉,有時又需要,因此需要加載php.ini文件蕊唐,將對應(yīng)配置放到配置文件中由擴(kuò)展加載屋摔。
    編輯php_wcl.h文件:
/*
    Declare any global variables you may need between the BEGIN
    and END macros here:
*/
ZEND_BEGIN_MODULE_GLOBALS(wcl)
    // filter_blank變量表示是否過濾空行,聲明擴(kuò)展內(nèi)的全局變量
    zend_long  filter_blank;
//  char *global_string;
ZEND_END_MODULE_GLOBALS(wcl)
  1. 編輯wcl.c文件
    添加配置項:
/* If you declare any globals in php_wcl.h uncomment this:*/
ZEND_DECLARE_MODULE_GLOBALS(wcl)

// Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
    // filter_blank變量賦默認(rèn)值0
    STD_PHP_INI_ENTRY("wcl.filter_blank",      "0", PHP_INI_ALL, OnUpdateBool, filter_blank, zend_wcl_globals, wcl_globals)
PHP_INI_END()
/* }}} */

wcl函數(shù)做如下修改替梨,使用WCL_G函數(shù)獲取php.ini中對應(yīng)配置項的值

    char ch, pre = '\n';
    zend_long lcount = 0;
    while ((ch = fgetc(fp)) != EOF) {
        if (ch == '\n') {
            // filter_blank in php.ini
            if (WCL_G(filter_blank) && pre == ch) {
                continue;
            }
            lcount++;
        }
        pre = ch;
    }
  1. 由于增加了配置項凡壤,現(xiàn)在要在擴(kuò)展啟動和銷毀時對配置項做相應(yīng)操作:
/* {{{ PHP_MINIT_FUNCTION
    配置項的注冊在該階段完成
 */
PHP_MINIT_FUNCTION(wcl)
{
    /* If you have INI entries, uncomment these lines */
    REGISTER_INI_ENTRIES();

    return SUCCESS;
}
/* }}} */


PHP_MSHUTDOWN_FUNCTION(wcl)
{
    /* uncomment this line if you have INI entries*/
    UNREGISTER_INI_ENTRIES();

    return SUCCESS;
}
  1. 編譯生成動態(tài)鏈接.so文件
    phpize命令需要安裝php-dev
phpize
./configure
sudo make
sudo make install
  1. 配置php.ini
    執(zhí)行上述過程不報錯那么擴(kuò)展對應(yīng)的目錄下會生成wcl.so文件,編輯php.ini
extension=wcl.so

[Wcl]
wcl.filter_blank = 1

到這里wcl擴(kuò)展就完成了耙替,可以重啟fpm然后直接使用wcl(filename)來測試輸出。

再多bb兩句曹体,php啟動常見兩種方式:cli和fpm俗扇,如果配置的是fpm的php.ini文件,那么修改php.ini后需要重啟fpm箕别,由此可見php.ini是在fpm啟動時候加載的铜幽,參見 https://www.php.net/manual/zh/configuration.file.php
關(guān)于PHP請求以及PHP擴(kuò)展的生命周期參見https://www.cnblogs.com/beatzeus/archive/2016/11/16/6071902.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市串稀,隨后出現(xiàn)的幾起案子除抛,更是在濱河造成了極大的恐慌,老刑警劉巖母截,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件到忽,死亡現(xiàn)場離奇詭異,居然都是意外死亡清寇,警方通過查閱死者的電腦和手機(jī)喘漏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來华烟,“玉大人翩迈,你說我怎么就攤上這事】梗” “怎么了负饲?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喂链。 經(jīng)常有香客問我返十,道長,這世上最難降的妖魔是什么椭微? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任吧慢,我火速辦了婚禮,結(jié)果婚禮上赏表,老公的妹妹穿的比我還像新娘检诗。我一直安慰自己匈仗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布逢慌。 她就那樣靜靜地躺著悠轩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪攻泼。 梳的紋絲不亂的頭發(fā)上火架,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音忙菠,去河邊找鬼何鸡。 笑死,一個胖子當(dāng)著我的面吹牛牛欢,可吹牛的內(nèi)容都是我干的骡男。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼傍睹,長吁一口氣:“原來是場噩夢啊……” “哼隔盛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拾稳,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤吮炕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后访得,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體龙亲,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年悍抑,在試婚紗的時候發(fā)現(xiàn)自己被綠了俱笛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡传趾,死狀恐怖迎膜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浆兰,我是刑警寧澤磕仅,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站簸呈,受9級特大地震影響榕订,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜕便,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一劫恒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦两嘴、人聲如沸丛楚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趣些。三九已至,卻和暖如春贰您,著一層夾襖步出監(jiān)牢的瞬間坏平,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工锦亦, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留舶替,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓杠园,卻偏偏與公主長得像顾瞪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子返劲,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容