php extname shared,PHP: 编写第一个PHP扩展
今天看了一些PHP擴(kuò)展的入門文章,很好的文章,但看的還是很吃力。主要是因?yàn)椴涣私馕恼吕镎f(shuō)的生命周期,內(nèi)存分配,SAPI這些概念。然后代碼里全是宏,如果不查源碼,和看天書(shū)沒(méi)什么區(qū)別。所以想記錄一下從源碼的角度分析 hello.c 這個(gè)文件的過(guò)程,其它文章里有的我就不重復(fù)了,我先放代碼,這里有一個(gè)部分和原文章不一樣。
隨便新建一個(gè)文件夾,里面包含下面3個(gè)文件:
config.m4
PHP_ARG_ENABLE(hello, whether to enable Hello
World support,
[ --enable-hello Enable Hello World support])
if test "$PHP_HELLO" = "yes"; then
AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])
PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fi
php_hello.h
#ifndef PHP_HELLO_H
#define PHP_HELLO_H 1
#define PHP_HELLO_WORLD_VERSION "1.0"
#define PHP_HELLO_WORLD_EXTNAME "hello"
PHP_FUNCTION(hello_world);
extern zend_module_entry hello_module_entry;
#define phpext_hello_ptr &hello_module_entry
#endif
hello.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_hello.h"
// 模塊所包含的函數(shù)列表信息
static zend_function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
{NULL, NULL, NULL}
};
// 模塊自身的相關(guān)信息
// 如模塊名,模塊包含的函數(shù),生命周期,版本號(hào)等
zend_module_entry hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_HELLO_WORLD_EXTNAME,
hello_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_HELLO_WORLD_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
// 與動(dòng)態(tài)加載有關(guān) Dynamic Loading,后面解釋
#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif
// 你的擴(kuò)展函數(shù)
PHP_FUNCTION(hello_world)
{
RETURN_STRING("Hello World", 1);
}
運(yùn)行下面的命令可以驗(yàn)證擴(kuò)展。
phpize
./configure
make
php -dextension=modules/hello.so -r "echo hello_world();"
和原文不同的是這里使用 zend_function_entry 而不是 function_entry。這個(gè)和 PHP 的版本有關(guān),不然編譯會(huì)出錯(cuò)。
我們先看這一段代碼
static zend_function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
{NULL, NULL, NULL}
};
如果你查看 PHP 官方文檔,也有可能會(huì)這樣寫。
static zend_function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
ZEND_FE_END
};
其實(shí)說(shuō)到底,把這些你看不懂的宏的定義找出來(lái),就好了,我們就先找 zend_function_entry,因?yàn)槲业脑创a在下面這個(gè)路徑下,所以我先 cd 過(guò)去。
/usr/local/Cellar/php56/5.6.32_8/include/php
然后用下面的命令找 zend_function_entry 的定義。
grep -rnw . -e 'zend_function_entry'
發(fā)現(xiàn)在 zend_API.h 這個(gè)文件。
./Zend/zend_API.h:41:} zend_function_entry;
源碼是一個(gè)結(jié)構(gòu)體,用到存儲(chǔ)函數(shù)的信息。
typedef struct _zend_function_entry {
const char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
const struct _zend_arg_info *arg_info;
zend_uint num_args;
zend_uint flags;
} zend_function_entry;
接著再看 PHP_FE,同理使用下面命令。
grep -rnw . -e 'PHP_FE'
得到下面的結(jié)果。
./main/php.h:352:#define PHP_FE ZEND_FE
再找 ZEND_FE,下面就不寫了,最后查到是這個(gè)定義。
#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeo
f(struct _zend_arg_info)-1), flags },
#define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)
其實(shí)就是一個(gè)關(guān)于函數(shù)結(jié)構(gòu)體的信息,和之前的 zend_function_entry 對(duì)應(yīng)。
再看 zend_module_entry 這一段代碼,其實(shí)做法也是參照上面的,#if ZEND_MODULE_API_NO >= 20010901 是用來(lái)判斷 api 版本是否大于等于 20010901 (這個(gè)是年月日),如果大于則在編譯期包含 STANDARD_MODULE_HEADER 這個(gè)宏,這些信息都可以在下面這個(gè)源文件找到,ZEND_MODULE_API_NO 這個(gè)宏也是定義這個(gè)文件中的。
zend_modules.h
最后說(shuō)說(shuō)這個(gè)
// 與動(dòng)態(tài)加載有關(guān) Dynamic Loading,后面解釋
#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif
其實(shí)我也不是很懂,查了 ZEND_GET_MODULE 這個(gè)宏,他是一個(gè)函數(shù),用于在運(yùn)行時(shí)供 Zend 引擎獲取模塊的名字。今天大概就到這里,下次再寫函數(shù)帶數(shù)的情況。
總結(jié)
以上是生活随笔為你收集整理的php extname shared,PHP: 编写第一个PHP扩展的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: matlab球面波衍射,单色点源矩孔菲涅
- 下一篇: 帝国扩展变量是哪个php,帝国CMS后台