PHP扩展开发

首先让我们在你PHP源码树的ext/目录下创建一个名叫hello的目录,并进入(chdir)到这个目录中。这个目录实际上可以放在任何地方,PHP源码树内或者PHP源码树外,但是我希望你把它放在源码树内为了接下来的文章使用。在这你需要创建三个文件:一个包含你hello_world函数的源文件,一个头文件,其中包含PHP加载你扩展时候所需的引用,一个配置文件,它会被phpize用来准备扩展的编译环境。

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"

static zend_function_entry hello_functions[] = {
    PHP_FE(hello_world, NULL)
    {NULL, NULL, NULL}
};

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
};

#ifdef COMPILE_DL_HELLO
    ZEND_GET_MODULE(hello)
#endif

PHP_FUNCTION(hello_world)
{
    RETURN_STRING("Hello World", 1);
}

以上只是一个PHP扩展的大体框架,扩展中的大部分代码只是简单的把几个文件关联在了一起。只有最后四句才像你之前在PHP脚本中调用的“实际代码”。实际上这个层级的代码和我们之前看到的PHP代码非常的相似,从字面上很容易理解:

  1. 声明一个名叫hello_world的函数
  2. 让那个函数返回一个字符串:“Hello World”
  3. ...额... 1? 那个1是做什么的?

回想一下ZE有一个先进的内存管理层,当脚本退出的时候确保分配的资源被释放掉。在内存管理领域,对同一块内存进行两次释放是大错特错的。这种做法叫做double freeing,是引起段错误的常见原因,因为它让程序去访问一个已经不属于自己的内存块。类似的,你不希望让ZE去释放一个静态字符串buffer(就像我们示例扩展中的”Hello World”),因为它是在程序空间,并不是属于任何进程的数据块。RETURN_STRING()假设任何传递给它的字符串都需要一个拷贝,所以它们可以在之后安全的释放掉。但是由于在一个内部函数中为字符串分配内存,动态填充,然后返回它,这是很平常,RETURN_STRING()允许我们来指定是否有必要对这个字符串值进行拷贝。为了更好的解释这个概念,接下来的代码片段的功能和上面的是一样的:

PHP_FUNCTION(hello_world)
{
    char *str;

    str = estrdup("Hello World");
    RETURN_STRING(str, 0);
}

在这个版本中,你手动为”Hello World”字符串分配了内存,最终返回给调用脚本,然后把内存“给了”RETURN_STRING,第二个参数值0说明不需要为这个字符串做拷贝。

建立你的扩展

这个练习的最后一步是把你的扩展编译成一个动态加载的模块。如果你已经正确的拷贝以上的例子,那么这个工作就是在ext/hello/目录下执行三个命令:

$ phpize
$ ./configure --enable-hello
$ make

在运行了这些命令之后,你将会在ext/hello/modules目录中发现一个hello.so文件。现在,可以像其他PHP扩展一样,你可以把它拷贝到你的扩展目录(默认是/usr/local/lib/php/extensions/,检查你的php.ini文件确定一下)中,然后在你的php.ini文件中加上extension=hello.so这一行,让扩展可以在PHP启动的时候被加载。对于CGI/CLI SAPI来说,这个意味着下一次PHP运行的时候就会生效;对于web server SAPI比如Apache来说,这个意味着web server下次被重启的时候生效。现在让我们以命令行的形式做一个尝试:

$ php -r 'echo hello_world();'

如果一切正常,你将会看到由这个脚本输出的Hello World,因为在你加载的扩展中已经定义的hello_world()函数会返回Hello World这个字符串,然后echo命令会打印出任何传递给它的东西。


转自:http://weizhifeng.net/write-php-extension-part1.html

详细学习参考:http://www.cunmou.com/phpbook/index.md

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值