PHP内核的学习--创建PHP扩展
开始看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扩展的更多相关文章
- Linux 内核list_head 学习
Linux 内核list_head 学习(一) http://www.cnblogs.com/zhuyp1015/archive/2012/06/02/2532240.html 在Linux内核中,提 ...
- Linux内核驱动学习(八)GPIO驱动模拟输出PWM
文章目录 前言 原理图 IO模拟输出PWM 设备树 驱动端 调试信息 实验结果 附录 前言 上一篇的学习中介绍了如何在用户空间直接操作GPIO,并写了一个脚本可以产生PWM.本篇的学习会将写一个驱动操 ...
- Spring MVC 学习 -- 创建过程
Spring MVC 学习 -- 创建过程 Spring MVC我们使用的时候会在web.xml中配置 <servlet> <servlet-name>SpringMVC< ...
- 教程:使用Diskpart创建、扩展或删除磁盘分区
在Windows Server环境下进行基本的磁盘操作时,管理员可以使用Disk Partition Utility或Diskpart等工具.后者是一个命令行解释器,可作为磁盘管理工具. 管理员可以使 ...
- MVC学习系列——ModelBinder扩展
在MVC系统中,我们接受数据,运用的是ModelBinder 的技术. MVC学习系列——ActionResult扩展在这个系列中,我们自定义了XmlResult的返回结果. 那么是不是意味着能POS ...
- 学习PHP C扩展之面向对象开发方式 (转)
PHP OOP面向对象之C语言开发方式 学习PHP C扩展有一段时间了,PHP手册里大部分讲的PHP的函数开发方式,网上找OOP资料比较少,想起上个月测试redis 的时候,下载PHP扩展redis源 ...
- Linux 内核使用的 GNU C 扩展
gcc核心扩展linuxforum(转)=========================== Linux 内核使用的 GNU C 扩展 =========================== GNC ...
- SQL Server 扩展事件(Extented Events)从入门到进阶(2)——在GUI中创建基础扩展事件
本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列 第一篇文章中提到了如何在Profiler中创建跟踪(trace),并以服务器端(server-side)跟 ...
- Robot Framework - 4 - 创建和扩展测试库的示例
创建和扩展Library的示例 示例:Check status on Linux OS 创建与使用library的基本步骤: 1--- library实现的内容和实现的方式 ...
随机推荐
- 我的iOS之路2
第一篇果然没人看呢...好吧...那就当笔记做吧...第一篇主要写的是生成了一个helloworld,可能也是和别人撞了,所以有点厌烦,连名字都改掉吧 好,开始写第二篇 之前做第一个应用程序的时候没有 ...
- IntelliLock
IntelliLock的使用说明: http://blog.csdn.net/gnicky/article/details/20737107 http://download.csdn.net/deta ...
- 从csdn博客搬家过来,请多关照!
之前一直在csdn博客,也写了不少关于java的文章,主要是学习java上的一些问题.想通过这种方式来加深对问题的认知,同时也可以帮助到志同道合的人,一起在编程的道路上共进,共勉.
- springMVC中一个controller多个方法
web.xml文件: <?xml version="1.0" encoding="UTF-8"?><web-app version=" ...
- HDU4430 Yukari's Birthday(枚举+二分)
Yukari's Birthday HDU4430 就是枚举+二分: 注意处理怎样判断溢出...(因为题目只要10^12) 先前还以为要用到快速幂和等比数列的快速求和(但肯定会超__int64) 而 ...
- XML dom
将文件解析为文档 三步过程 为了使用 XML 文件中的信息,必须解析文件以创建一个 Document 对象. Document 对象是一个接口,因而不能直接将它实例化:一般情况下,应用程序会相应使用一 ...
- C#设置打开新窗口的位置
C#打开窗口的位置的位置设置 引入命名空间using System.Drawing; 一.如果是打开在显示器正中间则很简单: Form对象.StartPosition = FormStartPosit ...
- 循序渐进做项目系列(2):最简单的C/S程序——消息异步调用与消息同步调用
上篇博客 循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法 实现了一个最简单的C/S程序,即让服务器来做加法.当时为了通俗易懂采用了消息异步调用的方式.今天我们要采用消息同步调用的方式 ...
- 设计模式之美:Mediator(中介者)
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Mediator 模式结构样式代码. 意图 用一个中介对象来封装一系列的对象交互. 中介者使各对象不需要显式地相互引用,从而使其 ...
- Form认证的几点说明
有的页面需要用户认证之后才可以进入,通常都是在Filter的OnActionExecuting方法中我们需要获取当前用户.有两种情况不必登录:1.用户是登录的,也就是认证过的.2.用户上次登录了,但没 ...