由php的call_user_func传reference引发的思考


Posted in PHP onJuly 23, 2010

问题的提出
网友bercmisir在院内留言,针对php手册中的call_user_func函数的文档一事,大致如下:
http://php.net/manual/en/function.call-user-func.php

其中parameter下有这样一句话:
Note: Note that the parameters for call_user_func() are not passed by reference.

简单地翻译一下,是说这个函数的参数是不能依靠引用来传递的。

还有一个例子:

error_reporting(E_ALL); 
function increment(&$var) 
{ 
$var++; 
} 
$a = 0; 
call_user_func('increment', $a); 
echo $a."\n"; 
call_user_func_array('increment', array(&$a)); // You can use this instead before PHP 5.3 
echo $a."\n"; 
?>

输出是:
0
1

而网友bercmisir的问题在于:
call_user_func('increment', $a);输出是0,而call_user_func('increment', &$a);却输出是1,明明说不能依靠引用来传递。

寻根溯源
然后再进一步寻根溯源,这个Note的信息其实是http://bugs.php.net/bug.php?id=24931这个bug中最后处理的结果。
并且在call_user_func('increment', &$a);虽然输出了1的结果,但一般情况下,会有一个警告信息:Deprecated: Call-time pass-by-reference has been deprecated。

这是什么原因呢?
先看一个例子:

error_reporting(E_ALL); 
function increment(&$var) 
{ 
$var++; 
} 
$x = 1; 
increment($x); 
echo $x; 
?>

结果为2,并且没有类似expected to be a reference, value given的警告信息,相反地,如果将第8行代码修改为&$x,将得到一个废除警告。从而得以验证,其实PHP在传递过程中,变量会根据形参需要的到底是引用还是值来自行决定传输的是引用还是值,并不需要显式地传递(相反显式传递是即将被废除的)。

继续深入
http://www.php.net/manual/en/language.references.pass.php
在php手册中,介绍引用的传递一节,在中间位置有一个Note说到:在函数调用时是不需要传引用的(也就是上节所说的显式调用),在5.3中如果显式调用会出来一个废除警告。

分析源码
有人说:在php中写入,everything is a reference。
查阅php源码,在./Zend/zend_compile.c的1579行有函数定义zend_do_pass_param。(php5.2.13)

其中有这样一句判断:
if (original_op == ZEND_SEND_REF && !CG(allow_call_time_pass_reference)) {打印废除警告。}
大概意思就是说,在传递的是引用,并且php.ini的allow_call_time_pass_reference为否的话,打印警告。
再看zend_do_pass_param使用的地方,可以发现是在parser阶段时,根据参数ZVAL结构体中元素的定义,来传递到底是var还是value还是reference。(php5.2.13 ./Zend/zend_language_parser.y/c 451/3593)

结论
引用其实类似linux里的文件硬链接一样,但和C语言中的指针是不相同的,在parser阶段php会根据上下文环境自行判断是传引用还是值。而本文所提到的call_user_function并不会自行判断传的是引用还是值。所以前面的例子call_user_function在传值的时候不管用,而在传引用的时候得出了正确结果(但其实还有一个废除警告)。

PHP 相关文章推荐
浅析echo(),print(),print_r(),return之间的区别
Nov 27 PHP
用PHP代替JS玩转DOM的思路及示例代码
Jun 15 PHP
php将字符串全部转换成大写或者小写的方法
Mar 17 PHP
php计算多维数组中所有值总和的方法
Jun 24 PHP
遍历指定目录,并存储目录内所有文件属性信息的php代码
Oct 28 PHP
PHP HTTP 认证实例详解
Nov 03 PHP
php、mysql查询当天,查询本周,查询本月的数据实例(字段是时间戳)
Feb 04 PHP
PHP实现的各类hash算法长度及性能测试实例
Aug 27 PHP
PHP 记录访客的浏览信息方法
Jan 29 PHP
php实现session共享的实例方法
Sep 19 PHP
设定php简写功能的方法
Nov 28 PHP
php设计模式之备忘模式分析【星际争霸游戏案例】
Mar 24 PHP
Google Voice 短信发送接口PHP开源版(2010.5更新)
Jul 22 #PHP
PHP 飞信好友免费短信API接口开源版
Jul 22 #PHP
PHP计划任务之关闭浏览器后仍然继续执行的函数
Jul 22 #PHP
PHP垃圾回收机制简单说明
Jul 22 #PHP
PHP多线程抓取网页实现代码
Jul 22 #PHP
php上传文件的增强函数
Jul 21 #PHP
php 模拟POST|GET操作实现代码
Jul 20 #PHP
You might like
深入php函数file_get_contents超时处理的方法详解
2013/06/03 PHP
PHP过滤黑名单关键字的方法
2014/12/01 PHP
PHP实现浏览器中直接输出图片的方法示例
2018/03/14 PHP
PHP实现动态删除XML数据的方法示例
2018/03/30 PHP
Yii2结合Workerman的websocket示例详解
2018/09/10 PHP
JQuery 简便实现页面元素数据验证功能
2007/03/24 Javascript
javascript将数组插入到另一个数组中的代码
2013/01/10 Javascript
jquery 跳到顶部和底部动画2句代码简单实现
2013/07/18 Javascript
js解析json读取List中的实体对象示例
2014/03/11 Javascript
使用JS画图之点、线、面
2015/01/12 Javascript
JavaScript中Number.MIN_VALUE属性的使用示例
2015/06/04 Javascript
js实现iPhone界面风格的单选框和复选框按钮实例
2015/08/18 Javascript
Jquery ajax基础教程
2015/11/20 Javascript
深入浅析JavaScript中数据共享和数据传递
2016/04/25 Javascript
JS实现重新加载当前页面
2016/11/29 Javascript
微信小程序开发经验总结(推荐)
2017/01/11 Javascript
js阻止移动端页面滚动的两种方法
2017/01/25 Javascript
Vue计算属性的学习笔记
2017/03/22 Javascript
微信小程序视图template模板引用的实例详解
2017/09/20 Javascript
Node.js 利用cheerio制作简单的网页爬虫示例
2018/03/01 Javascript
vue2中,根据list的id进入对应的详情页并修改title方法
2018/08/24 Javascript
layui实现左侧菜单点击右侧内容区显示
2019/07/26 Javascript
微信小程序自定义navigationBar顶部导航栏适配所有机型(附完整案例)
2020/04/26 Javascript
jquery实现异步文件上传ajaxfileupload.js
2020/10/23 jQuery
[02:16]DOTA2英雄基础教程 干扰者
2014/01/15 DOTA
django用户注册、登录、注销和用户扩展的示例
2018/03/19 Python
在PyCharm中实现关闭一个死循环程序的方法
2018/11/29 Python
python实现三次样条插值
2018/12/17 Python
python 2.7 检测一个网页是否能正常访问的方法
2018/12/26 Python
python 实现多线程下载m3u8格式视频并使用fmmpeg合并
2019/11/15 Python
详解Python中namedtuple的使用
2020/04/27 Python
Python Dataframe常见索引方式详解
2020/05/27 Python
中国电视购物:快乐购
2017/02/04 全球购物
西班牙最大的在线滑板和街头服饰商店:Fillow.net
2019/04/15 全球购物
盲山观后感
2015/06/11 职场文书
《秋天的雨》教学反思
2016/02/19 职场文书