PHP扩展开发--01.编写一个helloWorld扩展
为什么要用C扩展
C是静态编译的,执行效率比PHP代码高很多。同样的运算代码,使用C来开发,性能会比PHP要提升数百倍。
另外C扩展是在进程启动时加载的,PHP代码只能操作Request生命周期的数据,C扩展可操作的范围更广。
创建扩展骨架
##本例用的php版本的是5.3.3
cd php-5.3.3/ext/
./ext_skel --extname=myfun --proto=myfun.def
##执行成功后会生成myfun的编译文件
ls myfun/
config.m4 config.w32 CREDITS .cvsignore EXPERIMENTAL myfun.c myfun.php php_myfun.h tests
修改config.m4
config.m4中 dnl 为注释的意思
##动态编译选项,通过.so的方式链接,去掉dnl注释
PHP_ARG_WITH(myfun, for myfun support,
[ --with-myfun Include myfun support])
##静态编译选项,通过enable来启用,去掉dnl注释
PHP_ARG_ENABLE(myfun, whether to enable myfun support,
[ --enable-myfun Enable myfun support])
修改完成编译下
phpize
./configure --enable-myfun
make
make install
在myfun有个php的测试脚本,执行测试下
php -d enable_dl=On myfile.php
输出结果:
Functions available in the test extension:
confirm_myfun_compiled
Congratulations! You have successfully modified ext/myfun/config.m4. Module myfun is now compiled into PHP.
其实confirm_myfun_compiled是构建工具帮我们生成的测试函数
创建helloWorld函数
现在我们来创建属于自己的函数 helloWorld(),功能就是输出 Hello World!
vim myfun/php_myfun.h
##在PHP_FUNCTION(confirm_myfun_compiled); 下追加一行
PHP_FUNCTION(helloWorld);
实现helloworld实体
vim myfun/myfun.c
##zend_function_entry myfun_functions 补充要实现的函数
const zend_function_entry myfun_functions[] = {
PHP_FE(confirm_myfun_compiled, NULL) /* For testing, remove later. */
PHP_FE(helloWorld, NULL) /*这是补充的一行,末尾没有逗号*/
{NULL, NULL, NULL} /* Must be the last line in myfun_functions[] */
};
##在末尾实现helloworld的内容
PHP_FUNCTION(helloWorld)
{
php_printf("Hello World!\n");
RETURN_TRUE;
}
重新编译
./configure && make && make install
测试
php -d enable_dl=On -r "dl('myfun.so');helloWorld();"
Hello World!
php -d enable_dl=On -r "dl('myfun.so');print confirm_myfun_compiled('helloWorld');"
Congratulations! You have successfully modified ext/myfun/config.m4. Module helloWorld is now compiled into PHP.
头文件分析
#ifndef PHP_MYFUN_H
#define PHP_MYFUN_H
extern zend_module_entry myfun_module_entry;
#define phpext_myfun_ptr &myfun_module_entry
#ifdef PHP_WIN32
# define PHP_MYFUN_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_MYFUN_API __attribute__ ((visibility("default")))
#else
# define PHP_MYFUN_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(myfun); /*当PHP被装载时,模块启动函数即被引擎调用。这使得引擎做一些例如资源类型,注册INI变量等的一次初始化。*/
PHP_MSHUTDOWN_FUNCTION(myfun); /*当PHP完全关闭时,模块关闭函数即被引擎调用。通常用于注销INI条目*/
PHP_RINIT_FUNCTION(myfun); /*在每次PHP请求开始,请求前启动函数被调用。通常用于管理请求前逻辑。*/
PHP_RSHUTDOWN_FUNCTION(myfun); /*在每次PHP请求结束后,请求前关闭函数被调用。经常应用在清理请求前启动函数的逻辑。*/
PHP_MINFO_FUNCTION(myfun); /*调用phpinfo()时模块信息函数被呼叫,从而打印出模块信息。*/
PHP_FUNCTION(confirm_myfun_compiled); /* For testing, remove later. */
PHP_FUNCTION(helloWorld);
#ifdef ZTS
#define MYFUN_G(v) TSRMG(myfun_globals_id, zend_myfun_globals *, v)
#else
#define MYFUN_G(v) (myfun_globals.v)
#endif
#endif /* PHP_MYFUN_H */
confirm_myfun_compiled分析
PHP_FUNCTION(confirm_myfun_compiled) //使用了宏PHP_FUNCTION(),该宏可以生成一个适合于Zend引擎的函数原型
{
char *arg = NULL;
int arg_len, len;
char *strg;
//获得函数传递的参数
//第一个参数是传递给函数的参数个数。通常的做法是传给它ZEND_NUM_ARGS()。这是一个表示传递给函数参数总个数的宏。
//第二个参数是为了线程安全,总是传递TSRMLS_CC宏。
//第三个参数是一个字符串,指定了函数期望的参数类型,后面紧跟着需要随参数值更新的变量列表。因为PHP采用松散的变量定义和动态的类型判断,这样做就使得把不同类型的参数转化为期望的类型成为可能。例如,如果用户传递一个整数变量,可函数需要一个浮点数,那么zend_parse_parameters()就会自动地把整数转换为相应的浮点数。如果实际值无法转换成期望类型(比如整形到数组形),会触发一个警告。
/*
类型指示符
l long 符号整数
d double 浮点数
s char *, int 二进制字符串,长度
b zend_bool 逻辑型(1或0)
r zval * 资源(文件指针,数据库连接等)
a zval * 联合数组
o zval * 任何类型的对象
O zval * 指定类型的对象。需要提供目标对象的类类型
z zval * 无任何操作的zval
*/
//第四个参数为传递的参数数据的引用
//第五个参数为传递的参数个数
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { //获得函数传递的参数
return;
}
len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "myfun", arg);
/*
通过设置RETURN_type()的方式,将返回控制到PHP。下表解释了大多数存在的宏。
RETVAL_LONG(l) 整数
RETVAL_BOOL(b) 布尔数(1或0)
RETVAL_NULL() NULL
RETVAL_DOUBLE(d) 浮点数
RETVAL_STRING(s, dup) 字符串。如果dup为1,引擎会调用estrdup()重复s,使用拷贝。如果dup为0,就使用s
RETVAL_STRINGL(s, l, dup) 长度为l的字符串值。与上一个宏一样,但因为s的长度被指定,所以速度更快。
RETVAL_TRUE 返回布尔值true。注意到这个宏没有括号。
RETVAL_FALSE 返回布尔值false。注意到这个宏没有括号。
RETVAL_RESOURCE(r) 资源句柄。
*/
RETURN_STRINGL(strg, len, 0);
}
PHP扩展开发--01.编写一个helloWorld扩展的更多相关文章
- PHP扩展开发--编写一个helloWorld扩展
为什么要用C扩展 C是静态编译的,执行效率比PHP代码高很多.同样的运算代码,使用C来开发,性能会比PHP要提升数百倍. 另外C扩展是在进程启动时加载的,PHP代码只能操作Request生命周期的数据 ...
- Linux 下编写一个 PHP 扩展
假设需求 开发一个叫做 helloWord 的扩展. 扩展里有一个函数,helloWord(). echo helloWord('Tom'); //返回:Hello World: Tom 本地 ...
- PHP扩展开发01:第一个扩展【转】
我们先假设业务场景,是需要有这么一个扩展,提供一个叫ccvita_string的函数,他的主要作用是返回一段字符.(这个业务场景实在太假,大家就这么看看吧)对应的PHP代码可能是这样: functio ...
- 开发的第一个PHP扩展
下载php源码php-5.4.23.tar.gz,解压,进入/home/hubo/php-5.4.23/ext/扩展目录 wget http://cn2.php.net/get/php-5.4.23. ...
- PHP扩展开发01:第一个扩展
我们先假设业务场景,是需要有这么一个扩展,提供一个叫ccvita_string的函数,他的主要作用是返回一段字符.(这个业务场景实在太假,大家就这么看看吧)对应的PHP代码可能是这样: functio ...
- PHP扩展开发--02.包裹第三方的扩展
背景 也许最常见的PHP扩展是那些包裹第三方C库的扩展.这些扩展包括MySQL或Oracle的数据库服务库,libxml2的 XML技术库,ImageMagick 或GD的图形操纵库. 在本节中,我们 ...
- zynq学习01 新建一个Helloworld工程
1,好早买了块FPGA板,zynq 7010 .终极目标是完成相机图像采集及处理.一个Window C++程序猿才开始学FPGA,一个小菜鸟,准备转行. 2,关于这块板,卖家的官方资料学起来没劲.推荐 ...
- Chrome浏览器扩展开发系列之十七:扩展中可用的chrome.events API
chrome.events中定义了一些常见的事件类型,可以供Chrome浏览器扩展程序发出对应的事件对象. 对于关注的事件,首先要通过addListener()在对应的事件上注册监听器,示例如下: c ...
- Chrome浏览器扩展开发系列之八:Chrome扩展的数据存储
Google Chrome浏览器扩展可以使用如下任何一种存储机制: HTML5的localStorage API实现的本地存储(此处略) Google的chrome.storage.* API实现的浏 ...
随机推荐
- ZOJ 3946 Highway Project 贪心+最短路
题目链接: http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3946 题解: 用dijkstra跑单元最短路径,如果对于顶点v,存 ...
- Java 更改日期格式
import java.util.*; import java.text.*; public class TestDateFormat { public static void main(String ...
- SQL Server数据库复制
事务复制 事务复制是一种复制类型,对订阅服务器上应用的初始数据快照,然后当发布服务器上发生数据修改时,将捕获到个别的事务并传播到订阅服务. 事务复制的原理是先将发布服务器数据库中的初始快照发送到各订阅 ...
- MDL数据结构
微软的文档里对MDL的描述感觉语焉不详,这两天在找工作的间隙逆向+黑盒测试了一下MmBuildMdlForNonPagedPool,把得到的一些理解描述下来. 一.MDL数据结构 MDL是用来建立一块 ...
- 配置java环境 启动服务
1:查看当前的Java JDK版本,是否符合要求,下载的为2.4.4版本,因此满足条件 [root@7 ~]# java -version openjdk version "1.8.0_65 ...
- 还原 listagg/wm_concat 后的数据 pack_split_listatt ;
1.创建表并制作测试数据: --创建测试表 : CREATE TABLE split_table ( NAME ), ID ) ); --准备测试数据 : INSERT INTO split_tabl ...
- linux svn启动和关闭
linux svn启动和关闭 博客分类: linux系统 svnlinux 1,启动SVN sudo svnserve -d -r /home/data/svn/ 其中 -d 表示守护进程, -r ...
- excel表中判断A列与B列内容是否相同,相同的话在C列按条件输出!
判断两列数据是否相同,有以下几个函数判断(做笔记于此,方便以后查找): 1.=IF(AND(A4=B4),"相同","") 在C列输出相同字符 2.=IF(A1 ...
- 解决Lenovo(ldeapad)笔记本F1-F12功能键操作无效的问题
1.操作条件:Lenovo笔记本自带的“一键恢复”按钮 2.操作方法:上下键为切换选项,回车键(Enter)为确定选择 (1)在笔记本电脑关机状态下,使用曲别针或其他物件按下笔记本自带的“一键恢复按钮 ...
- C#中的静态常量(const)和动态常量(static和readonly)用法和区别
C#中有两种常量类型,分别为readonly(运行时常量)与const(编译时常量),本文将就这两种类型的不同特性进行比较并说明各自的适用场景.工作原理 readonly为运行时常量,程序运行时进行赋 ...