[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 已经是指针, 那么值就不对了.
./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 的使用建议相关推荐
- Delphi中DLL封装业务逻辑的实现
三层结构是开发C/S或B/S系统经常采用的策略,这种分层方式将系统分为用户服务.业务服务和数据服务三部分,能够解决客户端与服务器结构维护成本问题.改善客户端与服务器结构延展性问题:解决应用逻辑重复 ...
- OEA 中的业务控制器设计模式
对于业务逻辑的组织,个人认为,最好是使用 DDD(<Domain Driven Design>) 的方式.DDD 使用领域模型来表达实体间的关系,同时在应用层使用 Service 来组织各 ...
- MySQL:尽量不要用存储过程封装业务逻辑
本篇文章讨论并不是:不要使用存储过程,因为有些事情还是要存储过程来完成,不可能不用.而是关于:"业务逻辑是不是要封装在存储过程中实现,这样子php.java等就是调用存储过程". ...
- 减少存储过程封装业务逻辑-web开发与传统软件开发的思维模式不同
转:减少存储过程封装业务逻辑-web开发与传统软件开发的思维模式不同 本篇文章讨论并不是:不要使用存储过程,因为有些事情还是要存储过程来完成,不可能不用.而是关于:"业务逻辑是不是要封装在存 ...
- vue2项目中封装echarts地图的比较优雅的方式
以前写过 vue项目中封装echarts的比较优雅的方式,大屏可视化里面,除了数据图表很常用,显示省市地图区域也是很常用到的,这是姐妹篇. 区域地图选区域时,需要弹窗展示数据,样式是各种各样的,各种排 ...
- Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器
Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器实例的示例: public class AudioPlayer implements MediaPlayer.OnPre ...
- main.js中封装全局登录函数
main.js中封装全局登录函数 1. 在 main.js 中封装全局登录函数 通过 vue 对象的原型扩展,可以扩展一个函数,这样这个函数就可以在 每一个界面通过类似指向对象的方式,去访问这个函数. ...
- 【SSH进阶之路】一步步重构MVC实现Struts框架——封装业务逻辑和跳转路径(四)...
目录: [SSH进阶之路]Struts基本原理 + 实现简单登录(二) [SSH进阶之路]一步步重构MVC实现Struts框架--从一个简单MVC开始(三) [SSH进阶之路]一步步重构MVC实现St ...
- go get 的不再src目录中_GO语言基础进阶教程:包的使用
Go语言使用包(package)这种语法元素来组织源码,所有语法可见性均定义在package这个级别,与Java .python等语言相比,这算不上什么创新,但与C传统的include相比,则是显得& ...
最新文章
- 用SDM架构Cisco IOS ***图文详解全攻略(一)——easy ***
- pandas drop 删除行和列的方法
- mysql 高并发加锁_Mysql高并发加锁事务处理
- 2021-01-22 使用 Docker 打包 Python 项目
- Java注解全面解析
- 计算机处理信息的过程按先后顺序可表述为,信息加工理论按照信息处理的先后顺序将记忆区分为三个阶段系统;感觉记忆、()长时记忆。...
- LINUX yum用法
- Android开发学习——基础学习
- 测绘计算机编程在在道路中的应用,CASIO系列编程计算器在公路测量中的应用.doc...
- python循环语句笔记
- R语言生存分析之COX比例风险模型构建及亚组森林图绘制示例
- java-word模板导出
- 前端常见的浏览器兼容性问题及解决方案
- 【服务器数据恢复】断电导致raid信息丢失的磁盘阵列数据恢复案例
- redis中字符串(String)类型常见命令操作 (附有示例)
- nginx配置反向代理和负载均衡完结篇
- No.8 CA证书和SSH服务
- SwiftUI基础之Text格式化显示小数specifier
- 山东大学项目实训十六——可控音乐变压器Controllable Music Transformer
- c语言结构体世界杯,世界杯冷知识 | 12座球场的结构巡礼
热门文章
- python读取大数据量xml_[C#]_[使用微软OpenXmlSDK (OpenXmlReader)读取xlsx表格] 读取大数据量100万条数据Excel文件解决方案...
- LeetCode 426. 将二叉搜索树转化为排序的双向链表
- 【J2EE】第四章 SpringMVC
- vue 使用element 菜单与tab页联动
- 清结算系统的一些思考
- html学习文档-3、HTML元素
- pl/sql developer执行光标所在行
- 微信公众号开发入门教程第一篇
- 257. Binary Tree Paths
- android SQLite数据库(转)