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实现的浏 ...
随机推荐
- Python:文件操作总结1——文件基本操作
一.文件的操作流程 1.打开文件,得到文件句柄并赋值给一个变量 2.通过句柄对文件进行操作 3.关闭文件 二.文件的打开与关闭 A.文件的打开——open函数 语法:open(file[,mode[, ...
- IDEA + SSH OA 第一天(IDEA 文件夹类型了解)
回顾一下 IDEA 的文件夹的类型 设置文件夹方法 或者点击右上角的 文件夹的类型选择:可通过,右键文件夹,选择你要的类型: Sources Root : 源码的目录 Resources Root:源 ...
- JavaScript DOM编程艺术学习笔记-第二章JavaScript语法
一.JavaScript示例 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...
- .NET中的堆(Heap)和栈(Stack)的本质
计算机的内存可以分为代码块内存,Stack内存和Heap内存.代码块内存是在加载程序时存放程序机器代码的地方. 栈(Stack)一般存放函数内的局部变量. 堆(Heap)一般存放全局变量和类对象实例等 ...
- 初识ES6 解构
1.数组的解构 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构 例子: let [a, b, c] = [1, 2, 3]; console.log(a);//1cons ...
- java复利计算基本代码
源代码: public class Calculate { public static void main(String[] args){ double money = 1000; //本金 int ...
- 基于opencv的小波变换代码和图像结果
#include "stdafx.h" #include "WaveTransform.h" #include <math.h> #include ...
- postman md5加密 然后传给下一个接口作为参数调用
https://www.v2ex.com/api/nodes/show.json?name=python get请求 断言: tests["Body matches string" ...
- fiddler启动报错Unable to bind to port [8888],ErrorCode:10106
启动运行fiddler 报错,提示Unable to bind to port [8888],ErrorCode:10106 解决方式: 使用Fiddler或其他类似的监听工具出现这种错误时, Una ...
- 第138天:Web前端面试题总结(编程)
1.如何让一个盒子水平垂直居中 //已知宽高 <div class="div1"></div> <style> .div1{ width:400 ...