ReflectionFunction(Method)引用参数导致Invocation failed
浏览:1225次 出处信息
今天同事反馈一个问题, PHP5.2.x在使用反射做函数包装的时候, 得到”Invocation failed”的异常, 而使用call_user_func代替则不会,
原逻辑太复杂, 经过精简以后可重现异常的代码如下(使用ReflectionFunction为例, ReflectionMethod类似):
- function who(&$name) {
- echo $name;
- }
- $name = "laruence";
- $method = new ReflectionFunction("who");
- $method->invokeArgs(array($name));
- //异常:
- Uncaught exception 'ReflectionException' with message
- 'Invocation of function who() failed'
找原因过程中歧途我就不多言了, 最后跟踪到invokeArgs会调用Zend引擎提供的zend_call_function, 而在zend_call_function中, 有如下一段逻辑引起我的怀疑(注意注释部分):
- int zend_call_function(zend_fcall_info *fci
- , zend_fcall_info_cache *fci_cache TSRMLS_DC) {
- //以上省略
- if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i+1)
- && !PZVAL_IS_REF(*fci->params[i])) {
- /*如果形参是引用传递 并且参数不是引用 */
- if ((*fci->params[i])->refcount>1) {
- /*如果参数的refcount大于1 */
- zval *new_zval;
- if (fci->no_separation) {
- /*如果不容许执行分离操作, 则返回失败 */
- return FAILURE;
- }
- //以下省略
也就是说, 如果一个申明为引用传递的参数不为引用传递, 而refcount又大于1, 那么在不容许分离的条件下, 就会导致zend_call_function失败返回(如果对refcount和变量分离不了解, 可以参看我之前的文章深入理解PHP原理之变量分离/引用).
经过验证, 果然invokeArgs在构造zend_fcall_info fci的时候, 是禁止separation的, 所以导致zend_call_funcion返回FAILURE.
而使用call_user_func则不会是因为,call_user_function不考虑no_separation直接分离, 这一点在PHP手册中, call_user_func中是有说明的:
- Note: Note that the parameters for call_user_func() are not passed by reference
找到了原因, 那解决的办法, 也就容易了:
- function who(&$name) {
- echo $name;
- }
- $name = "laruence";
- $method = new ReflectionFunction("who");
- $method->invokeArgs(array(&$name)); //is_ref
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
扫一扫订阅我的微信号:IT技术博客大学习
<< 前一篇:使用PHP将大文件导入到数据库中..
后一篇:深入理解PHP之匿名函数 >>
文章信息
- 作者:雪候鸟 来源: 风雪之隅
- 标签: Invocation ReflectionFuncti
- 发布时间:2010-06-23 12:58:37
近3天十大热文
- [65] Oracle MTS模式下 进程地址与会话信
- [65] Go Reflect 性能
- [64] 如何拿下简短的域名
- [59] android 开发入门
- [59] IOS安全–浅谈关于IOS加固的几种方法
- [58] 图书馆的世界纪录
- [58] 【社会化设计】自我(self)部分――欢迎区
- [53] 视觉调整-设计师 vs. 逻辑
- [47] 界面设计速成
- [46] 读书笔记-壹百度:百度十年千倍的29条法则