[php-src]扩展中封装业务与 call_user_function 的使用建议

内容均以php5.6.14为例.

从一个封装 uniqid 的例子来讲。

/* {{{ wrapper of uniqid */
PHP_FUNCTION(fox)
{    // #1.
    zval *prefix, *more = NULL;
    zval function, *params[2] = {0};

    // #2.
    if ( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &prefix, &more) == FAILURE ) {
        RETURN_FALSE;
    }

    params[0] = prefix;
    if (more) {
        params[1] = more;
    }

    // #3.
    ZVAL_STRING(&function, "uniqid", 0);
    // #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), 0);
}
/* }}} */

#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[1] = 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 已经是指针, 那么值就不对了.

Thats all.

开发文档:https://github.com/farwish/php-core-hack

Link:http://www.cnblogs.com/farwish/p/5635429.html

@黑眼诗人  <www.farwish.com>

时间: 2024-12-17 04:53:51

[php-src]扩展中封装业务与 call_user_function 的使用建议的相关文章

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

本篇文章讨论并不是:不要使用存储过程,因为有些事情还是要存储过程来完成,不可能不用.而是关于:"业务逻辑是不是要封装在存储过程中实现,这样子php.java等就是调用存储过程". 业务逻辑,通俗说就是:比如要取数据的操作,取出会员编号为x的数据,原来我们一般是封装成函数,或者直接编写sql语句查询.现在是交给数据库的存储过程去完成. +------------------------------------------------------------ 写这篇文章的缘由 +-----

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

目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制和通信方式 3.Chrome扩展开发之三——Chrome扩展中的数据本地存储和下载 4.Chrome扩展开发之四——Gmail API的简单介绍 5.Chrome扩展开发之五——OAuth2的理解 6.Chrome扩展开发之六——GmailAssist核心功能的实现(包括Gmail API的使用中的

直播开始:&#39;云榨汁机&#39;诞生记--聊聊JavaScript中的&#39;业务建模&#39;

闭包是JavaScript中的一个重要特性,在之前的博文中,我们说闭包是一个'看似简单,其实很有内涵'的特性.当我们用JavaScript来实现相对复杂的业务建模时,我们可以如何利用'闭包'这个特性呢?JavaScript中的'原型继承',又可以解决业务建模中的哪些问题呢?今天我们就通过一家'榨汁机工厂'生产设计'榨汁机'的故事,来聊一聊'闭包'和'原型继承'在业务建模中的作用.现在直播开始: 1> 工厂默认选用A型刀头方案制造榨汁机 例子当中我们主要涉及到2个函数:1.榨汁机的生产工厂(Jui

封装业务类

1.什么是业务类? 业务类:专门处理某项业务(事情) 2.业务类的作用? 把一些业务的业务逻辑封装起来,其它类需要处理这些业务的时候,直接调用业务类的方法就可以了 大大减少了其它类中的代码量,让代码看起来更整洁,可读性更好 3.业务类的规范 3.1 在类的上面,注明这个类的功能(作用) 让其它人一看到这个类就知道是干什么用的,减少沟通成本 1 // Created by XT on 16/7/31. 2 // Copyright © 2016年 XT. All rights reserved.

【SSH进阶之路】一步步重构MVC实现Struts框架——封装业务逻辑和跳转路径(四)

目录: [SSH进阶之路]Struts基本原理 + 实现简单登录(二) [SSH进阶之路]一步步重构MVC实现Struts框架--从一个简单MVC开始(三) [SSH进阶之路]一步步重构MVC实现Struts框架--封装业务逻辑和跳转路径(四) [SSH进阶之路]一步步重构MVC实现Struts框架--彻底去掉逻辑判断(五) [SSH进阶之路]一步步重构MVC实现Struts框架--完善转向页面,大功告成(六) Struts的第二篇博客[SSH进阶之路]Struts基本原理 + 实现简单登录(二

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

控制器的作用 我们知道,在AngularJS中,实现数据绑定的核心是scope对象.那么控制器又有什么用呢? 简单地说,没有控制器/controller,我们没有地方定义业务模型. 回忆下ng-init指令.我们可以使用ng-init指令在scope对象上定义数据,比如: <div ng-init="sb={name:'somebody',gender:'male',age:28}"> </div> 但是,ng-init的值是一个AngularJS表达式,没有办

在DLL动态链接库中封装VCL的MDI子窗体

在DLL动态链接库中封装VCL的MDI子窗体不多说了,看代码就应该明白了,曾经我遇到的问题,现在放出来大家共享! 这里是工程文件的部分: 在DLL中封装MDI子窗体需要重写DLL入口函数,具体代码如下: var DllApp: TApplication;//定义保存原DLL的TApplication对象 DllScr: TScreen;//定义保存原DLL的TScreen对象 procedure UnProcDll(Reason: Integer); register;//重新定义DLL入口函数

在DLL中封装的VCL窗体Tab键响应的问题

在DLL中的子窗体不会响应Tab按键的,这个时候就需要手动去指定Tab键的操作,但是前提是主窗体要向这个窗体发送一个消息,一个Tab键按下的消息.基本顺序是这样的: 1. 主窗体用Hook技术捕获Tab按键并向活动子窗体发送一个Tab键按下的消息 2. 子窗体手动定义一个Tab键被按下的处理(需要用到FormKeyDown事件). 3. 移动到下一个焦点的WinAPI函数:Perform(WM_NEXTDLGCTL,0,0); 4.移动到上一个焦点的函数:Perform(WM_NEXTDLGCT

IIS Web服务扩展中没有Asp.net 2.0

服务器上安装了ASP.NET v2.0组件,但是在IIS的Web服务扩展中并没有找到ASP.NET v2.050727这项,这导致基于.NET2.0开发的网页都无法正常浏览. 解决方法:打开IIS,转至Web服务扩展中,点击右侧窗口任务下的“添加一个新的Web服务扩展”,在弹出的窗口中,点击添加,然后找到 x:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll(x为系统安装盘符, 一盘为C),再点击确定按钮保存设置,最后再设置