开始看PHP内核也有一段时间了,现在开始边学边总结,今天就总结一下如何创建自己的PHP扩展。

我的环境如下:

系统:Ubuntu 14.04

php版本:5.5.19

参考摘录:用C/C++扩展你的PHP

PHP取得成功的一个主要原因之一是它拥有大量的可用扩展。web开发者无论有何种需求,这种需求最有可能在PHP发行包里找到。PHP发行包包括支持各种数据库,图形文件格式,压缩,XML技术扩展在内的许多扩展。

扩展API的引入使PHP3取得了巨大的进展,扩展API机制使PHP开发社区很容易的开发出几十种扩展。现在,两个版本过去了,API仍然和PHP3时的非常相似。扩展主要的思想是:尽可能的从扩展编写者那里隐藏PHP的内部机制和脚本引擎本身,仅仅需要开发者熟悉API。

有两个理由需要自己编写PHP扩展。第一个理由是:PHP需要支持一项她还未支持的技术。这通常包括包裹一些现成的C函数库,以便提供PHP接口。例如,如果一个叫FooBase的数据库已推出市场,你需要建立一个PHP扩展帮助你从PHP里调用FooBase的C函数库。这个工作可能仅由一个人完成,然后被整个PHP社区共享(如果你愿意的话)。第二个不是很普遍的理由是:你需要从性能或功能的原因考虑来编写一些商业逻辑。

假设你正在开发一个网站,需要一个把字符串重复n次的函数。下面是用PHP写的例子:

function util_str_repeat($string, $n){
$result = "";
for($i = 0; $i < $n; $i++){
$result .= $string;
}
return $result;
} util_str_repeat("One", 3);// returns "OneOneOne".
util_str_repeat("One", 1);// returns "One".

假设由于一些奇怪的原因,你需要时常调用这个函数,而且还要传给函数很长的字符串和大值n。这意味着在脚本里有相当巨大的字符串连接量和内存重新分配过程,以至显著地降低脚本执行速度。如果有一个函数能够更快地分配大量且足够的内存来存放结果字符串,然后把$string重复n次,就不需要在每次循环迭代中分配内存。

为扩展建立函数的第一步是写一个函数定义文件,该函数定义文件定义了扩展对外提供的函数原形。该例中,定义函数只有一行函数原形util_str_repeat() :

string util_str_repeat(string str, int n)

函数定义文件的一般格式是一个函数一行。你可以定义可选参数和使用大量的PHP类型,包括: bool, float, int, array等。

保存为util.def文件至PHP原代码目录树下(即与ext_skel文件放在同一目录下,我的目录是/usr/share/php5/)。

然后就是通过扩展骨架(skeleton)构造器运行函数定义文件的时机了。该构造器脚本就是ext_skel。假设你把函数定义保存在一个叫做util.def的文件里,而且你希望把扩展取名为util,运行下面的命令来建立扩展骨架:

sudo ./ext_skel --extname=util --proto=util.def

执行之后,我这里报了如下错误:

./ext_skel: : cd: can't cd to /usr/lib/php5/skeleton
Creating directory util
awk: cannot open /create_stubs (No such file or directory)
Creating basic files: config.m4 config.w32 .svnignore util.c./ext_skel: : ./ext_skel: cannot open /skeleton.c: No such file
php_util.h./ext_skel: : ./ext_skel: cannot open /php_skeleton.h: No such file
CREDITS./ext_skel: : ./ext_skel: cannot open /CREDITS: No such file
EXPERIMENTAL./ext_skel: : ./ext_skel: cannot open /EXPERIMENTAL: No such file
tests/.phpt./ext_skel: : ./ext_skel: cannot open /tests/.phpt: No such file
util.php./ext_skel: : ./ext_skel: cannot open /skeleton.php: No such file
rm: cannot remove ‘function_entries’: No such file or directory
rm: cannot remove ‘function_declarations’: No such file or directory
rm: cannot remove ‘function_stubs’: No such file or directory
[done]. To use your new extension, you will have to execute the following steps: . $ cd ..
. $ vi ext/util/config.m4
. $ ./buildconf
. $ ./configure --[with|enable]-util
. $ make
. $ ./php -f ext/util/util.php
. $ vi ext/util/util.c
. $ make Repeat steps - until you are satisfied with ext/util/config.m4 and
step confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.

很明显是/usr/lib/php5/skeleton路径的错误,编辑ext_skel文件,将/usr/lib/php5/skeleton修改为/usr/share/php5/skeleton,然后移除掉生成的util文件夹,再次执行之前的命令,成功后提示如下:

Creating directory util
Creating basic files: config.m4 config.w32 .svnignore util.c php_util.h CREDITS EXPERIMENTAL tests/.phpt util.php [done]. To use your new extension, you will have to execute the following steps: . $ cd ..
. $ vi ext/util/config.m4
. $ ./buildconf
. $ ./configure --[with|enable]-util
. $ make
. $ ./php -f ext/util/util.php
. $ vi ext/util/util.c
. $ make Repeat steps - until you are satisfied with ext/util/config.m4 and
step confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.

然后采用静态编译的方式编译扩展。为了使扩展能够被编译,需要修改扩展目录util/下的config.m4文件。扩展没有包裹任何外部的C库,你需要添加支持–enable-util配置开关到PHP编译系统里(–with-extension 开关用于那些需要用户指定相关C库路径的扩展)。找到如下内容:

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

将前面的dnl 去掉,修改为如下结果:

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

然后修改util.c文件,找到如下代码:

PHP_FUNCTION(util_str_repeat)
{
char *str = NULL;
int argc = ZEND_NUM_ARGS();
int str_len;
long n; if (zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n) == FAILURE)
return; php_error(E_WARNING, "util_str_repeat: not yet implemented");
}

将其修改为如下代码:

PHP_FUNCTION(util_str_repeat)
{
char *str = NULL;
int argc = ZEND_NUM_ARGS();
int str_len;
long n;
char *result; /* Points to resulting string */
char *ptr; /* Points at the next location we want to copy to */
int result_length; /* Length of resulting string */ if (zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n) == FAILURE)
return; /* Calculate length of result */
result_length = (str_len * n);
/* Allocate memory for result */
result = (char *) emalloc(result_length + );
/* Point at the beginning of the result */
ptr = result; while (n--) {
/* Copy str to the result */
memcpy(ptr, str, str_len);
/* Increment ptr to point at the next position we want to write to */
ptr += str_len;
}
/* Null terminate the result. Always null-terminate your strings
even if they are binary strings */
*ptr = '\0';
/* Return result to the scripting engine without duplicating it*/
RETURN_STRINGL(result, result_length, );
}

里面的具体内容,就不在这里说了,之后会慢慢写到。

然后就是编译,安装。在util目录下,命令如下(命令可能都需要加sudo):

phpize
./configure
make
make test
make install

然后配置生成的扩展文件,在php5.5版本中,进入到/etc/php5/mods-available目录下,创建util.ini文件,写入如下内容:

extension=util.so

然后enable util扩展

sudo php5enmod util

最后,重启php-fpm

sudo service php5-fpm restart

创建一个php文件,测试一下,测试文件如下:

<?php
for ($i = 1; $i <= 3; $i++) {
print util_str_repeat("CraryPrimitiveMan ", $i);
print "\n";
}
?>

执行结果如下:

CraryPrimitiveMan
CraryPrimitiveMan CraryPrimitiveMan
CraryPrimitiveMan CraryPrimitiveMan CraryPrimitiveMan

这样我们就成功创建了一个包含简单的PHP函数的扩展。

盗图一张~~

今天就先到这里~~

PHP内核的学习--创建PHP扩展的更多相关文章

  1. Linux 内核list_head 学习

    Linux 内核list_head 学习(一) http://www.cnblogs.com/zhuyp1015/archive/2012/06/02/2532240.html 在Linux内核中,提 ...

  2. Linux内核驱动学习(八)GPIO驱动模拟输出PWM

    文章目录 前言 原理图 IO模拟输出PWM 设备树 驱动端 调试信息 实验结果 附录 前言 上一篇的学习中介绍了如何在用户空间直接操作GPIO,并写了一个脚本可以产生PWM.本篇的学习会将写一个驱动操 ...

  3. Spring MVC 学习 -- 创建过程

    Spring MVC 学习 -- 创建过程 Spring MVC我们使用的时候会在web.xml中配置 <servlet> <servlet-name>SpringMVC< ...

  4. 教程:使用Diskpart创建、扩展或删除磁盘分区

    在Windows Server环境下进行基本的磁盘操作时,管理员可以使用Disk Partition Utility或Diskpart等工具.后者是一个命令行解释器,可作为磁盘管理工具. 管理员可以使 ...

  5. MVC学习系列——ModelBinder扩展

    在MVC系统中,我们接受数据,运用的是ModelBinder 的技术. MVC学习系列——ActionResult扩展在这个系列中,我们自定义了XmlResult的返回结果. 那么是不是意味着能POS ...

  6. 学习PHP C扩展之面向对象开发方式 (转)

    PHP OOP面向对象之C语言开发方式 学习PHP C扩展有一段时间了,PHP手册里大部分讲的PHP的函数开发方式,网上找OOP资料比较少,想起上个月测试redis 的时候,下载PHP扩展redis源 ...

  7. Linux 内核使用的 GNU C 扩展

    gcc核心扩展linuxforum(转)=========================== Linux 内核使用的 GNU C 扩展 =========================== GNC ...

  8. SQL Server 扩展事件(Extented Events)从入门到进阶(2)——在GUI中创建基础扩展事件

    本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列 第一篇文章中提到了如何在Profiler中创建跟踪(trace),并以服务器端(server-side)跟 ...

  9. Robot Framework - 4 - 创建和扩展测试库的示例

    创建和扩展Library的示例 示例:Check status on Linux OS 创建与使用library的基本步骤:           1--- library实现的内容和实现的方式     ...

随机推荐

  1. 使用属性android:onClick,出现异常NoSuchMethodException

    在Activity中注册点击事件有两种方式,setOnClickListener或在xml中设置控件的android:onClick="gotoSecond"属性,在Activit ...

  2. 在WPF的WebBrowser控件中屏蔽脚本错误的提示

    在WPF中使用WebBrowser控件显示网页时,经常会报脚本错误的提示,如何屏蔽掉这些错误提示呢.方法是定义如下方法: public void SuppressScriptErrors(WebBro ...

  3. iOS 7 UI Transition – Porting View Controller Layouts from iOS 6

    http://www.mobinett.com/2013/08/19/ios7-ui-transition-porting-view-controller-layouts-ios6/

  4. selenium 切换窗口 每次成功code

    最近用了网络上别人的一段切换窗口的code每次成功了,不错,学习 // 根据Title切换新窗口 public boolean switchToWindow_Title(WebDriver drive ...

  5. php中explode与split的区别介绍

    php中explode与split的区别介绍 作者: 字体:[增加 减小] 类型:转载 今天在使用split时遇到一些问题.还是对函数理解不深刻,特写出来做个记 首先来看下两个方法的定义: 函数原型: ...

  6. centos6 一个vlan配置多ip地址

    添加vlan [root@localhost network-scripts]# vconfig add eth1 109 配置文件,此处配置了vlan109使用子接口进行多ip配置: [root@l ...

  7. 设计模式之美:Behavioral Patterns(行为型模式)

    行为型模式涉及到算法和对象间职责的分配. 行为模式不仅描述对象或类的模式,还描述它们之间的通信模式. 这些模式刻划了在运行时难以跟踪的复杂的控制流.它们将你的注意力从控制流转移到对象间的联系方式上来. ...

  8. Wix 安装部署教程(九) --用WPF做安装界面

    经常安装PC端的应用,特别是重装系统之后,大致分为两类.一类像QQ,搜狗输入法这样的.分三步走的:第一个页面可以自定义安装路径和软件许可.第二个页面显示安装进度条,第三个页面推荐其他应用.先不管人家怎 ...

  9. Nim教程【十四】

    网友@沉没捕鱼,赞助了一台服务器 这个系列的教程写完之后,我们就要开始着手搭建Nim的社区了~ 异常 Nim中的异常类型是对象类型 根据惯例,Nim中的异常类型的命名都应该以Error后缀结尾 在sy ...

  10. 在github上写个人简历——先弄个主页

    起因 不知道园友们在使用智联招聘等网站填写简历的时候对要求输入的内容有没有一种无力感,不吐槽了反正就一句话,按照它提供的格式我没法儿写简历,而且面试的时候总会被问道有没有自己作品,哥们儿天天上班,下班 ...