内容均以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 的使用建议的更多相关文章

  1. JS组件系列——在ABP中封装BootstrapTable

    前言:关于ABP框架,博主关注差不多有两年了吧,一直迟迟没有尝试.一方面博主觉得像这种复杂的开发框架肯定有它的过人之处,系统的稳定性和健壮性比一般的开源框架肯定强很多,可是另一方面每每想到它繁琐的封装 ...

  2. 减少存储过程封装业务逻辑-web开发与传统软件开发的思维模式不同

    本篇文章讨论并不是:不要使用存储过程,因为有些事情还是要存储过程来完成,不可能不用.而是关于:"业务逻辑是不是要封装在存储过程中实现,这样子php.java等就是调用存储过程". ...

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

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

  4. Chrome扩展开发之三——Chrome扩展中的数据本地存储和下载

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

  5. 直播开始:'云榨汁机'诞生记--聊聊JavaScript中的'业务建模'

    闭包是JavaScript中的一个重要特性,在之前的博文中,我们说闭包是一个'看似简单,其实很有内涵'的特性.当我们用JavaScript来实现相对复杂的业务建模时,我们可以如何利用'闭包'这个特性呢 ...

  6. AngularJS之使用控制器封装业务逻辑

    AngularJS之使用控制器封装业务逻辑 控制器的作用 我们知道,在AngularJS中,实现数据绑定的核心是scope对象.那么控制器又有什么用呢? 简单地说,没有控制器/controller,我 ...

  7. main.js中封装全局登录函数

    1. 在 main.js 中封装全局登录函数 通过 vue 对象的原型扩展,可以扩展一个函数,这样这个函数就可以在每一个界面通过类似指向对象的方式,去访问这个函数. 如下是 main.js 扩展的函数 ...

  8. 示例:WPF中自定义StoryBoarService在代码中封装StoryBoard、Animation用于简化动画编写

    原文:示例:WPF中自定义StoryBoarService在代码中封装StoryBoard.Animation用于简化动画编写 一.目的:通过对StoryBoard和Animation的封装来简化动画 ...

  9. PHP 使用 mcrypt 扩展中的 mcrypt_encrypt() 和 mcrypt_decrypt() 对数据进行加密和解密

    <?php /* 使用 mcrypt 扩展中的 mcrypt_encrypt() 和 mcrypt_decrypt() 对数据进行加密和解密 */ // 加密 $algorithm = MCRY ...

随机推荐

  1. 数据库FMDB-sql

    1.首先要先导入第三方类库FMdatabase. 2.获得存放数据库文件的沙盒地址. #pragma mark - 创建数据库 - (void)createAndInitDatabase { NSSt ...

  2. C#小写数字金额转换成大写人民币金额的算法

    C#小写数字金额转换成大写人民币金额的算法 第一种方法: using System.Text.RegularExpressions;//首先引入命名空间 private string DaXie(st ...

  3. smarty 模板的入门使用

    <?php require_once 'inc/libs/Smarty.class.php'; $s=new Smarty(); // echo $s::SMARTY_VERSION; // e ...

  4. Idea安装及简单配置

    1. 安装JDK   设置环境变量   JAVA_HOME    C:\Program Files\Java\jdk1.8.0_45   CLASSPATH    .;%JAVA_HOME%\lib; ...

  5. win10 重装应用商店

    管理员模式打开powershell 命令窗口,输入以下重装应用商店的命令.亲测有效,我刚安装回来了. Get-AppXPackage *WindowsStore* -AllUsers | Foreac ...

  6. SQL Server 常用函数介绍

    --聚合函数 count( * | 字段名) --统计数据表中的数据总数sum( 表达式 | 字段名) --计算表达式或字段名中数据的和,表达式或字段名的数据类型要求是数值型avg( 表达式 | 字段 ...

  7. java能不能自己写一个类叫java.lang.System/String正确答案

    原文: http://www.wfuyu.com/php/22254.html 未做测试 ! 最近学习了下java类加载相干的知识.然后看到网上有1道面试题是 能不能自己写个类叫java.lang.S ...

  8. callback转Promise

    环境:  nodejs - v6.2.0 const fs = require('fs'); let Promise = require('bluebird'); let readSync = fun ...

  9. JSON与XML优缺点对比分析

    本文从各个方面向大家对比展示了json和xml的优缺点,十分的全面细致,有需要的小伙伴可以参考下. 1. 定义介绍 1.1 XML定义 扩展标记语言 (Extensible Markup Langua ...

  10. [转]eclipse最佳设置

    设置工作空间的项目编码, 防止出现乱码     Window - Preferences - General - Workspace     将"Text file encoding&quo ...