[php-src]扩展中封装业务与 call_user_function 的使用建议
内容均以php5.6.14为例.
从一个封装 uniqid 的例子来讲。
/* {{{ wrapper of uniqid */
PHP_FUNCTION(fox)
{
// #1.
zval *prefix, *more = NULL;
zval function, *params[] = {}; // #2.
if ( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &prefix, &more) == FAILURE ) {
RETURN_FALSE;
} params[] = prefix;
if (more) {
params[] = more;
} // #3.
ZVAL_STRING(&function, "uniqid", );
// #4.
if ( call_user_function(EG(function_table), NULL, &function, return_value, ZEND_NUM_ARGS(), params TSRMLS_CC) == FAILURE ) {
if (return_value) {
zval_dtor(return_value);
}
zend_error(E_WARNING, "%s() calling %s() failed.", get_active_function_name(TSRMLS_C), Z_STRVAL(function));
RETURN_FALSE;
} RETURN_STRING(Z_STRVAL_P(return_value), );
}
/* }}} */
#1.
zval 不赋值默认是非空,不要随意给 声明的 zval 赋值为 NULL,除非你知道自己在干什么,比方用在判断是否有传参;
如果你想对可选的参数使用默认值 farwish,可以像下面这样 (非用于上例):
if (more == NULL) {
MAKE_STD_ZVAL(more);
Z_STRVAL_P(more) = "farwish";
Z_STRLEN_P(more) = strlen("farwish");
Z_TYPE_P(more) = IS_STRING;
}
params[] = more;
还有别忘了 call_user_function 中的参数个数就不能再用 ZEND_NUM_ARGS(),写固定值 2 就可以了。
#2.
接收的参数类型必须用双引号包裹,为了避免其它地方也遇到这种错误,最好后面统一都用双引号。
如果接收的参数含 char *name 类型的, 别忘了要有 uint *len 跟在它后面传入。
#3. #4.
如果开头声明的是 zval *function, 并且 ZVAL_STRING 赋值 和 call_user_function 的调用都传 function, 编译能通过, 但是使用会segmentaion fault;测试证明, ZVAL_STRING 第一个参数一定是指向 zval 的地址, 而不是简单的传 zval *, 因为宏中做了 zval *__z = (z) 这么一件事, 如果 z 已经是指针, 那么值就不对了.
./Zend/zend_execute_API.c:575
int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC)
zval function_name, retval_ptr;
Thats all.
开发文档:https://github.com/farwish/php-core-hack
Link:http://www.cnblogs.com/farwish/p/5635429.html
[php-src]扩展中封装业务与 call_user_function 的使用建议的更多相关文章
- JS组件系列——在ABP中封装BootstrapTable
前言:关于ABP框架,博主关注差不多有两年了吧,一直迟迟没有尝试.一方面博主觉得像这种复杂的开发框架肯定有它的过人之处,系统的稳定性和健壮性比一般的开源框架肯定强很多,可是另一方面每每想到它繁琐的封装 ...
- 减少存储过程封装业务逻辑-web开发与传统软件开发的思维模式不同
本篇文章讨论并不是:不要使用存储过程,因为有些事情还是要存储过程来完成,不可能不用.而是关于:"业务逻辑是不是要封装在存储过程中实现,这样子php.java等就是调用存储过程". ...
- Chrome扩展开发之二——Chrome扩展中脚本的运行机制和通信方式
目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...
- Chrome扩展开发之三——Chrome扩展中的数据本地存储和下载
目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...
- 直播开始:'云榨汁机'诞生记--聊聊JavaScript中的'业务建模'
闭包是JavaScript中的一个重要特性,在之前的博文中,我们说闭包是一个'看似简单,其实很有内涵'的特性.当我们用JavaScript来实现相对复杂的业务建模时,我们可以如何利用'闭包'这个特性呢 ...
- AngularJS之使用控制器封装业务逻辑
AngularJS之使用控制器封装业务逻辑 控制器的作用 我们知道,在AngularJS中,实现数据绑定的核心是scope对象.那么控制器又有什么用呢? 简单地说,没有控制器/controller,我 ...
- main.js中封装全局登录函数
1. 在 main.js 中封装全局登录函数 通过 vue 对象的原型扩展,可以扩展一个函数,这样这个函数就可以在每一个界面通过类似指向对象的方式,去访问这个函数. 如下是 main.js 扩展的函数 ...
- 示例:WPF中自定义StoryBoarService在代码中封装StoryBoard、Animation用于简化动画编写
原文:示例:WPF中自定义StoryBoarService在代码中封装StoryBoard.Animation用于简化动画编写 一.目的:通过对StoryBoard和Animation的封装来简化动画 ...
- PHP 使用 mcrypt 扩展中的 mcrypt_encrypt() 和 mcrypt_decrypt() 对数据进行加密和解密
<?php /* 使用 mcrypt 扩展中的 mcrypt_encrypt() 和 mcrypt_decrypt() 对数据进行加密和解密 */ // 加密 $algorithm = MCRY ...
随机推荐
- 用vs2013(cpu-only)调试caffe的mnist
在调试Mnist例子之前,首先需要用vs2013编译好caffe.详情请参见: [caffe-Windows]caffe+VS2013+Windows无GPU快速配置教程 按照上述教程编译好caffe ...
- 重走java--Step 2
java基础语法(一) 1.java基本数据类型 byte:1个字节,8bit有符号数据类型boolean:2个字节,16bit布尔数值char:2个字节,16bit的Unicode字符类型int:4 ...
- java单例模式
单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点. 使用场景:在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现"不良反映" ...
- .NET 配置项扩展
using System; using System.Configuration; namespace ConsoleApplication3 { /* web.config 或 app.config ...
- myeclicps开发web时候复制一个工程改名字后执行出现404错误
当部署的时候会出现如下的警告,此时请按照如下的方法解决: 1.选择要运行的工程,右击-->properties-->在上边的搜索框中搜索web,选中web,将Web Context-roo ...
- iOS开发 代码 或 <Home+Power>截屏
1. 截屏的两种简单方法, 注意这两种截图方法,都必须在视图完全加载完成后才能截图,即在 viewDidAppear 方法之后截屏,否则无法得到想要的截屏效果 (1) 利用绘图方法 renderI ...
- SQL Server更新表(用一张表的数据更新另一张表的数据)
a) 写法轻松,更新效率高: update table1 set field1=table2.field1,field2=table2.field2 from table2 where table1. ...
- [转载] Android Bander设计与实现 - 设计篇
本文转载自: http://blog.csdn.net/chenxiancool/article/details/17454593 摘要 Binder是Android系统进程间通信(IPC)方式之一. ...
- apache目录浏览
DocumentRoot "/Library/WebServer/Documents" <Directory "/Library/WebServer/Documen ...
- 反射——反射API,使用反射创建数组
反射API Java.lang.Reflect库 ① Class类与Java.lang.Reflect类库一起对反射的概念进行支持. ② java.lang包下: a) Cla ...