有时候我们需要更改PHP内置的一些方法,有时候我们要写一些自己的拓展服务于PHP。
为何要写PHP拓展?
答案很简单了,实现快、公用、灵活的目的.
今天这里就说一下如何来独立开发PHP拓展.
一、创建一个PHP文件 ext_test.php

<?php
/**
* @Desc   : 增加拓展bravedu方法 bravedu.so
* @Author : BraveDu
* @Date   : 2016-02-04
*/
  echo  $test = bravedu(‘bravedu’);

二、php ext_test.php 执行
不用说了,肯定报错.找不到方法
Fatal error: Call to undefined function bravedu()

三、创建PHP拓展大体分为如下几个步骤

3.1 切换到我们PHP的安装包

cd /root/LAMP/php-5.6.17/ext

3.2 用户PHP为我们提供了拓展代码生成工具 ext_skel,生成我们的拓展包

    ./ext_skel --extname=bravedu
    执行结果:
Creating directory bravedu
Creating basic files: config.m4 config.w32 .gitignore bravedu.c php_bravedu.h CREDITS EXPERIMENTAL tests/001.phpt bravedu.php [done].

To use your new extension, you will have to execute the following steps:

1.  $ cd ..
2.  $ vi ext/bravedu/config.m4
3.  $ ./buildconf
4.  $ ./configure --[with|enable]-bravedu
5.  $ make
6.  $ ./sapi/cli/php -f ext/bravedu/bravedu.php
7.  $ vi ext/bravedu/bravedu.c
8.  $ make
此时会在ext 目录下生成 bravedu 的拓展目录

3.3 进入拓展目录 cd bravedu 目录

3.4 修改配置文件 config.m4

vim bravedu/config.m4

看配置文件中这段注释,dnl 是注释的意思, 如果你所编写的扩展如果依赖其它的扩展或者lib库,需要去掉PHP_ARG_WITH相关代码的注释。否则,去掉 PHP_ARG_ENABLE 相关代码段的注释。我们编写的扩展不需要依赖其他的扩展和lib库。因此,我们去掉PHP_ARG_ENABLE前面的注释。
dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.

dnl If your extension references something external, use with:

dnl PHP_ARG_WITH(bravedu, for bravedu support,
dnl Make sure that the comment is aligned:
dnl [  --with-bravedu             Include bravedu support])

dnl Otherwise use enable:

dnl PHP_ARG_ENABLE(bravedu, whether to enable bravedu support,
dnl Make sure that the comment is aligned:
dnl [  --enable-bravedu           Enable bravedu support])


修改后的代码如下:

dnl Otherwise use enable:

PHP_ARG_ENABLE(bravedu, whether to enable bravedu support,
Make sure that the comment is aligned:
[  --enable-bravedu           Enable bravedu support])

3.5 在我们拓展的C语言原文件中加入我们要封装的 bravedu 方法

查找:PHP_FUNCTION(confirm_bravedu_compiled),在此方法上面增加我们的要封装的函数

PHP_FUNCTION(bravedu)
{
    char *name;
    int name_len;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
        RETURN_NULL();
    }
    php_printf("Hello %s ", name);
    RETURN_TRUE;
}

这里对 zend 的函数解释下,并且为何用php_printf?
借助前辈们写的一段注释,是这么说的

大多数zend_parse_parameters()块看起来是总是一样的。ZEND_NUM_ARGS()告诉Zend引擎要取得的参数的信息,TSRMLS_CC用来确保线程安全,返回值将被检查是SUCCESS还是FAILURE。通常情况下,zend_parse_parameters()将返回SUCCESS;然而,如果调用脚本试图传入太多或太少的参数,或者传入的参数不能被转为适当的类型,Zend会自动输出一条错误信息并优雅地将控制权还给调用脚本。

本例指定s表明此函数期望只传入一个参数,而且该参数应该被转为string数据类型并装入通过地址传入的char*变量(也就是通过name)。

注意,还有一个int变量通过地址被传入zend_parse_parameters()。这使Zend引擎提供字符串的字节长度,如此二进制安全的函数不再需要依赖strlen(name)确定字符串的长度。实际上使用strlen(name)甚至得不到正确的结果,因为name可能在字符串结束之前包含一个或多个NULL字符。

一旦你的函数确切地得到了name参数,接下来要做的就是把它作为正式问候语的一部分输出。注意,用的是php_printf()而不是更熟悉的printf()。使用这个函数是有重要的理由的。首先,它允许字符串通过PHP的缓冲机制的处理,该机制除了可以缓冲数据,还可执行额外的处理,比如gzip压缩。其次,虽然stdout是极佳的输出目标,使用CLI或CGI时,多数SAPI期望通过特定的pipe或socket传来输出。所以,试图只是通过printf()写入stdout可能导致数据丢失、次序颠倒或者被破坏,因为它绕过了预处理。

最后,函数通过返回TRUE将控制权还给调用程序。你可以没有显式地返回值(默认是NULL)而是让控制到达你的函数的结尾,但这是坏习惯。函数如果不传回任何有意义的结果,应该返回TRUE以说明:“完成任务,一切正常”。

查找:const zend_function_entry bravedu_functions[] = { 函数体
在 PHP_FE(confirm_bravedu_compiled 上面增加我们编写的方法
PHP_FE(bravedu,NULL)
代码如下:

const zend_function_entry bravedu_functions[] = {
        PHP_FE(bravedu,NULL)
        PHP_FE(confirm_bravedu_compiled,        NULL)           /* For testing, remove later. */
        PHP_FE_END      /* Must be the last line in bravedu_functions[] */
};

3.6 链接、编译、安装

注意了: 仍然是在 bravedu 这个插件目录下
phpize
./configure
make && make install
执行结果:
Build complete.
Don't forget to run 'make test'.
Installing shared extensions:     /usr/local/php5.6.17/lib/php/extensions/no-debug-zts-20131226/

3.7 修改PHP.ini , 引入拓展
extension=/usr/local/php5.6.17/lib/php/extensions/no-debug-zts-20131226/bravedu.so

3.8 重启apache 即可生效 可以通过 php -m | grep bravedu 即可查看到组件

四、题外话

假如拓展源文件中有写错的字符,需要修改,修改后怎么办.
解决方案:
只需要进入你的拓展中修改bravedu.c 源文件, 修改后直接make && make install 立即生效,不需要重启环境.

五、执行结果

php ext_text.php  
执行结果:  Hello bravedu .  

哈哈.