为什么要用C扩展

C是静态编译的,执行效率比PHP代码高很多。同样的运算代码,使用C来开发,性能会比PHP要提升数百倍。

另外C扩展是在进程启动时加载的,PHP代码只能操作Request生命周期的数据,C扩展可操作的范围更广。

下载PHP7.1.1扩展

1.下载地址: http://php.net/get/php-7.1.1.tar.bz2/from/a/mirror

2.下载后进行解压

创建扩展骨架

##本例用的是php7.1.1
cd ext
./ext_skel --extname=helloworld

修改config.m4

把下面几行注释打开,config.m4中 dnl 为注释的意思

##动态编译选项,通过.so的方式链接,去掉dnl注释:

PHP_ARG_WITH(helloworld, for helloworld support,
Make sure that the comment is aligned:
[ --with-helloworld Include helloworld support]) ##静态编译选项,通过enable来启用,去掉dnl注释: PHP_ARG_ENABLE(helloworld, whether to enable helloworld support,
Make sure that the comment is aligned:
[ --enable-helloworld Enable helloworld support])

修改完成编译下

phpize
#这里用自己的php-config文件位置
./configure --with-php-config=./configure --with-php-config=/Applications/MAMP/bin/php/php7.1.1/bin/php-config
make && make install
make test #测试
#编辑php.ini,加上helloworld扩展
extension=helloworld.so

在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, , "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, );
}

PHP扩展开发--编写一个helloWorld扩展的更多相关文章

  1. PHP扩展开发--01.编写一个helloWorld扩展

    为什么要用C扩展 C是静态编译的,执行效率比PHP代码高很多.同样的运算代码,使用C来开发,性能会比PHP要提升数百倍. 另外C扩展是在进程启动时加载的,PHP代码只能操作Request生命周期的数据 ...

  2. Chrome扩展开发之二——Chrome扩展中脚本的运行机制和通信方式

    目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...

  3. 学习spring2--跟我一起学Spring 3(3)–使用Spring开发第一个HelloWorld应用

    http://www.importnew.com/13246.html     首页 所有文章 资讯 Web 架构 基础技术 书籍 教程 我要投稿 更多频道 » - 导航条 - 首页 所有文章 资讯 ...

  4. Linux 下编写一个 PHP 扩展

        假设需求 开发一个叫做 helloWord 的扩展. 扩展里有一个函数,helloWord(). echo helloWord('Tom'); //返回:Hello World: Tom 本地 ...

  5. 使用Spring开发第一个HelloWorld应用

    http://www.importnew.com/13246.html 让我们用Spring来写第一个应用程序吧. 完成这一章要求: 熟悉Java语言 设置好Spring的环境 熟悉简单的Eclips ...

  6. PHP扩展开发01:第一个扩展【转】

    我们先假设业务场景,是需要有这么一个扩展,提供一个叫ccvita_string的函数,他的主要作用是返回一段字符.(这个业务场景实在太假,大家就这么看看吧)对应的PHP代码可能是这样: functio ...

  7. PHP扩展开发01:第一个扩展

    我们先假设业务场景,是需要有这么一个扩展,提供一个叫ccvita_string的函数,他的主要作用是返回一段字符.(这个业务场景实在太假,大家就这么看看吧)对应的PHP代码可能是这样: functio ...

  8. php扩展开发-实现一个简易的哈希表

    从一个简易的哈希表入手,会让你更好的理解php的哈希表,他们的本质是一样的,只是php的哈希表做了更多的功能扩展,php的哈希表是php语言的一个重要核心,大量的内核代码使用到哈希表. #includ ...

  9. Jmeter扩展组件开发(2) - 扩展开发第一个demo的实现

    maven工程src目录介绍 main:写代码 main/java:写Java代码 main/resources:写配置文件 test:写测试代码 test/java demo实现 创建Package ...

随机推荐

  1. 主流蓝牙芯片盘点,Nordic/TI/博通哪家强?

    无线通信技术自19世纪中期诞生以来,从使用狼烟.火炬.闪光镜.信号弹等在视距内传输信息,到1838年塞缪尔・莫尔斯发明电报网,再到电报网被电话取代,再到几十年后的1895年马可尼首次从英国怀特岛到30 ...

  2. BAE静态文件问题

    这几天想在bae上架一个自己的博客,但是老是访问不到静态文件文件,都要没有办法了,最后看了这篇博客,受到了启发,知道了问题所在: 我自己的原始的app.conf的配置如下: handlers: - u ...

  3. DOM之节点类型加例子

    DOM= Document Object Model,文档对象模型,DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构.换句话说,这是表示和处理一个HTML或XML文档的常用方法.D ...

  4. Alpha冲刺第6天

    Alpha第六天 1.团队成员 郑西坤 031602542 (队长) 陈俊杰 031602504 陈顺兴 031602505 张胜男 031602540 廖钰萍 031602323 雷光游 03160 ...

  5. Linux命令(四)删除文件 rm

    用户可以使用 rm 命令删除不需要的文件. rm 可以删除文件或目录,并且支持通配符. 如果目录中存在其它文件则会递归删除. 删除软链接只是删除链接,对应的文件或目录不会被删除. 软链接类似于 win ...

  6. Oracle 数据库执行 操作系统的命令

    1 Linux环境下面的处理 在sqlplus 里面 添加一个 ! 就可以执行 但是 因为Oracle 必须为非root用户 所以很多命令可能无法执行: 2. Windows 环境执行命令的方式 是在 ...

  7. poj2082 Terrible Sets(单调栈)

    Description Let N be the set of all natural numbers {0 , 1 , 2 , . . . }, and R be the set of all re ...

  8. King's Quest POJ - 1904(强连通分量)

    建图:王子u喜欢女孩v,则u到v连一条边.对于给出的初始完美匹配,王子u与女孩v匹配,则v到u连一条边.然后求SCC. 显然对于同一个SCC中王子数目和女孩数目是相等的,并且从某个王子出发能够到达所有 ...

  9. KUR-Couriers

    题目链接: QwQ Solution: 以权值为下标,对每个点建树 对于x点,以它为根的树涵盖的是1到x区间内每个数出现的次数 Code: #include<bits/stdc++.h> ...

  10. 【题解】 Test 买水的ACX(套路)

    题目描述: ACX在××信竞组学会信息竞赛,但是他的同学都很巨,于是要他去买水,结果来到某个买水的商店(奇奇怪怪的商店). 一天,ACX买了 N 个容量可以认为是无限大的瓶子,初始时每个瓶子里有 1  ...