PHP擴充套件開發系列01 – 我要成為一名老司機
1. 關於擴充套件的教程貌似挺全了,為啥還寫?
-
記錄下我寫擴充套件的歷程
-
自認為會寫的更容易理解
-
我的宗旨就是 “先用再識” 程式碼寫著寫著就知道原理了 或者說邊寫邊學, 邊學邊寫
2. 那麼你首先要具備哪些預備知識? 答:你需要先過科目一
-
C 為啥放第一位?
-
PHP 不會?那寫什麼PHP擴充套件?
-
PHP的編譯安裝
-
phpize 和 php-config 這個靠你們自己去了解了
-
關於PHP編譯 前期非必須,但是要知道的 (no-debug, non-zts, debug, zts)
-
問?搜? — 有時候不一定要問或者搜才能找到解決的答案。
-
找! — 找出別人擴充套件真麼寫的 (php-src/ext)。不但有答案,還有思想。
至於 PHP ZEND 原理啥的, 很重要, 很重要, 很重要, 但是這裡暫時放一邊,沒事可以去了解了解。
3. 先看看剛上車的司機是什麼樣的? (示例程式碼) 最後有註釋版的
程式碼說明
-
這是一個很簡單的擴充套件, 簡單到沒有功能
-
副檔名稱 laosiji
-
目前看來 這只是一個只會裝B(啥都不會)的司機
-
三個檔案
-
config.m4
-
php_laosiji.h
-
laosiji.c
config.m4
PHP_ARG_ENABLE(
laosiji,
whether to enable laosiji support,
[ --enable-laosiji Enable laosiji support]
)
if test "$PHP_LAOSIJI" != "no"; then
PHP_NEW_EXTENSION(laosiji, laosiji.c, $ext_shared)
fi
php_laosiji.h
#define PHP_LAOSIJI_EXTNAME "laosiji"
#define PHP_LAOSIJI_VERSION "1.0.0"
// 載入config.h,如果配置了的話
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// 載入php標頭檔案
#include "php.h"
laosiji.c
#include "php_laosiji.h"
// module entry
zend_module_entry laosiji_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_LAOSIJI_EXTNAME, /* 副檔名稱 */
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
PHP_LAOSIJI_VERSION, /* 擴充套件版本 */
#endif
STANDARD_MODULE_PROPERTIES};
#ifdef COMPILE_DL_LAOSIJI
ZEND_GET_MODULE(laosiji)
#endif
5. 作為司機的一本基本開車動作 (擴充套件的編譯安裝等)
-
phpize
-
./configure 這裡要注意下 php-config
-
make
-
make install
-
載入 .so 擴充套件檔案
6. 點火啟動 試試我們的擴充套件
<?php
var_dump(extension_loaded(`laosiji`));
// 自己去了解下 dl 函式
// @ 只是為了不出現那煩人的 提示
// 為了避免不必要的麻煩 建議在 php.ini 載入 擴充套件
@dl(`laosiji.so`);
var_dump(extension_loaded(`laosiji`));
7. 小節
差不多就到這裡了。這次主要說了下寫PHP擴充套件要準備的一些基本知識。當然有些人可能對上面提到部分概念沒深入瞭解。
比如 PHP不同編譯方式(debug, nts..)<這個你看別的擴充套件原始碼的時候就會注意到>、phpize、php-config 具體作用。
phpize、php-config 一定要注意,這裡提醒你這回遇到坑。
後面再來慢慢學習老司機的各種姿勢。包括,函式,函式引數,函式返回值,物件,類,名稱空間等等等。
8. 註釋版程式碼
config.m4
dnl dnl 開頭的語句 屬於註釋內容
dnl PHP_ARG_ENABLE 函式有三個引數
dnl 第一個引數 laosiji 副檔名稱 (不用加引號)
dnl 第二個引數 執行 ./configure 指令碼時顯示的內容
dnl 第三個引數 呼叫 ./configure --help 顯示的幫助資訊
dnl 最後去了接下 PHP_ARG_WITH 這裡就先不提了
PHP_ARG_ENABLE(
laosiji,
whether to enable laosiji support,
[ --enable-laosiji Enable laosiji support]
)
if test "$PHP_LAOSIJI" != "no"; then
dnl PHP_NEW_EXTENSION 函式宣告 擴充套件的名稱、需要的原始檔名、擴充套件的編譯形式
dnl 第一個引數 擴充套件的名稱
dnl 第 2 。。 n-1 個引數 需要的原始檔名
dnl 最後的$ext_shared引數用來宣告這個擴充套件不是一個靜態模組,而是在php執行時動態載入的。
dnl 如果我們的擴充套件使用了多個檔案,便可以將這多個檔名羅列在函式的引數裡,如:
dnl PHP_NEW_EXTENSION(laosiji, laosiji.c, laosiji_2.c, laosiji_3.c, $ext_shared)
PHP_NEW_EXTENSION(laosiji, laosiji.c, $ext_shared)
fi
php_laosiji.h
// 定義 擴充套件相關的巨集 比如版本號 副檔名稱等等。。
#define PHP_LAOSIJI_EXTNAME "laosiji"
#define PHP_LAOSIJI_VERSION "1.0.0"
// 載入config.h,如果配置了的話
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// 載入php標頭檔案
// 這個 很有必要哈
#include "php.h"
laosiji.c
#include "php_laosiji.h"
// module entry
// 1. laosiji_module_entry 副檔名稱_module_entry
// 2. PHP_LAOSIJI_EXTNAME /* 副檔名稱 */
// 3. PHP_LAOSIJI_VERSION, /* 擴充套件版本 */
// 那些 NULL ?
// 第一個你要記住 /* Functions */ 這行 想想 php 中的函式
// 第二個你要記住 /* MINIT */ 想想 class && object
// 第三個你要記住 MINIT MSHUTDOWN RINIT RSHUTDOWN MINFO 慢慢來 不著急
zend_module_entry laosiji_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_LAOSIJI_EXTNAME, /* 副檔名稱 */
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
PHP_LAOSIJI_VERSION, /* 擴充套件版本 */
#endif
STANDARD_MODULE_PROPERTIES};
#ifdef COMPILE_DL_LAOSIJI
ZEND_GET_MODULE(laosiji)
#endif