PHP 引用是个坏习惯


Posted in PHP onMarch 12, 2010
function binsearch(&$arr, $key, $value) 
{ 
$low = 0; 
$high = count($arr); 
while ($low <= $high) { 
$mid = floor($low + ($high - $low) / 2); 
$item = $arr[$mid][$key]; 
if ($item == $value) { 
return $mid; 
} else if ($value > $item) { 
$low = $mid + 1; 
} else { 
$high = $mid - 1; 
} 
} 
return false; 
}

在这里,$mid 采用了先减后加的方法计算,目的是为了防止整数的溢出。不是故意写复杂了。
我用下面的代码进行测试:
$data = array(); 
for ($i = 0; $i < 1000000; $i++) 
{ 
$data[] = array("sq" => $i * 2); 
} 
var_dump(binsearch($data, "sq", 10000));

发现,binsearch 的时候,总是要花个 0.2s左右。理论上来说,100万的数据,最多也就是循环20次。怎么会这样慢呢。
后来监控了一下内存,data 数组 占用了 230M 的内存。而 binsearch 的时候,占用了60K 的内存。但是,理论上来说,binsearch
不应该占用如此多的内存。因为,我觉得,我已经用引用了,根本就没有对data 的结构进行修改。
我也是百思不得其解,后来,我把引用参数去掉,居然 binsearch 只要 0.0002s ,看来是引用耗费了大量的cpu 资源。
PHP 内部遵循一个copy on write 的原则。实际上这个引用是多余的。
但是为什么,加了引用速度会变慢呢?今天重点就谈谈这个问题。明白道理后,大家一定知道怎么用引用了。
如果在binsearch 调用前,直接 $a = &$data,这个引用的速度会非常的快。看来肯定不是引用本身产生的问题。
这个问题,实际上涉及了zend 引擎如何管理PHP变量。
先看下面的问题:
<?php 
function demo(&$a, &$b) { $a =& $b; } 
$a = 1; 
$b = 2; 
demo($a, $b); 
$b = 3; 
print $a; 
?>

$a 输出是多少呢?不错,是2. 不过,我一开始觉得是3。
那么怎么解释上面这个问题呢?
实际上,函数的参数引用是这样进行的。
$tmp = $a; 
$a1 = &$tmp; 
$a = $tmp; 
unset($a1, $tmp);

这里,引用的实际上是一个临时变量。这个时候,$tmp 是带引用属性的,而$a 变量不是带引用属性的。
根据zend引擎管理内存的方法,在内部,不能用一个zval 来表示,必须强制分离这个zval。
用这样的理解方法,上面的问题就解决了。函数内部,不会改变函数外部的引用特性。这也是PHP
不赞成用 calltime_by_ref 的原因,而选择上面如此低效的拷贝方法。
下面的分析,也能证明,在传递参数时,的确发生了拷贝。
在 binsearch 函数里面。
$data[0] = 1;
这样,就会发生一次$data 所在zval 的拷贝。内存使用量 就是 60K。和函数调用加引用一模一样。
可能很多人会疑问,为什么不是多了230M呢,这其实就是PHP的高明之处,数组Key 对应的是一个zval的指针。(内部是一个哈希表)
所以,只要把这些指针复制一遍就就好了,数据不用复制。但是,100万的PHP 哈希表实际上要占用 50M 内存。为什么只有60K呢。
在 binsearch 函数的外面,运行
$t = $data; 
$t[0] = 1; 
unset($t);

果然,多了60K 的内存。估计和PHP的内存管理机制有关系。
现在一切都明白了吧!今天,想了好几个小时,才把这个问题想通,不敢独享。
函数中的引用不是给你传参数方便的,而是让你实现,一个函数,可以有多个返回值的,所以,最好不要画蛇添足。
实际上,用引用它会降低性能。
PHP 相关文章推荐
使用无限生命期Session的方法
Oct 09 PHP
不错的PHP学习之php4与php5之间会穿梭一点点感悟
May 03 PHP
PHP XML备份Mysql数据库
May 27 PHP
PHP 时间转换Unix时间戳代码
Jan 22 PHP
php正则表达匹配中文问题分析小结
Mar 25 PHP
(PHP实现)只使用++运算实现加法,减法,乘法,除法
Jun 27 PHP
WordPress后台中实现图片上传功能的实例讲解
Jan 11 PHP
Thinkphp事务操作实例(推荐)
Apr 01 PHP
PHP将身份证正反面两张照片合成一张图片的代码
Apr 08 PHP
php使用ftp实现文件上传与下载功能
Jul 21 PHP
PHP用PDO如何封装简单易用的DB类详解
Jul 30 PHP
windows系统php环境安装swoole具体步骤
Mar 04 PHP
PHP 页面编码声明方法详解(header或meta)
Mar 12 #PHP
用PHP获取Google AJAX Search API 数据的代码
Mar 12 #PHP
PHP开启gzip页面压缩实例代码
Mar 11 #PHP
php checkdate、getdate等日期时间函数操作详解
Mar 11 #PHP
PHP 5.3新特性命名空间规则解析及高级功能
Mar 11 #PHP
PHP Memcached + APC + 文件缓存封装实现代码
Mar 11 #PHP
了解Joomla 这款来自国外的php网站管理系统
Mar 11 #PHP
You might like
《Re:从零开始的异世界生活 冰结之绊》
2020/04/09 日漫
php echo()和print()、require()和include()函数区别说明
2010/03/27 PHP
PHP截断标题且兼容utf8和gb2312编码
2013/09/22 PHP
PHP PDOStatement::fetchColumn讲解
2019/01/31 PHP
PHP+Redis开发的书签案例实战详解
2019/07/09 PHP
用window.location.href实现刷新另个框架页面
2007/03/07 Javascript
发一个自己用JS写的实用看图工具实现代码
2008/07/26 Javascript
JQery 渐变图片导航效果代码 漂亮
2010/01/01 Javascript
JavaScript内核之基本概念
2011/10/21 Javascript
JQuery的read函数与js的onload不同方式实现
2013/03/18 Javascript
JS打开层/关闭层/移动层动画效果的实例代码
2013/05/11 Javascript
JavaScript将数字转换成大写中文的方法
2015/03/23 Javascript
有关easyui-layout中的收缩层无法显示标题的解决办法
2016/05/10 Javascript
移动端jQuery修正Web页面滑动时div问题的两则实例
2016/05/30 Javascript
js获取上传文件的绝对路径实现方法
2016/08/02 Javascript
JSONP和批量操作功能的实现方法
2016/08/21 Javascript
JavaScript之RegExp_动力节点Java学院整理
2017/06/29 Javascript
Three.js利用dat.GUI如何简化试验流程详解
2017/09/26 Javascript
Vue SSR 组件加载问题
2018/05/02 Javascript
使用Python进行新浪微博的mid和url互相转换实例(10进制和62进制互算)
2014/04/25 Python
Python彩色化Linux的命令行终端界面的代码实例分享
2016/07/02 Python
详解python中字典的循环遍历的两种方式
2017/02/07 Python
Django配置celery(非djcelery)执行异步任务和定时任务
2018/07/16 Python
python itchat实现调用微信接口的第三方模块方法
2019/06/11 Python
python基于递归解决背包问题详解
2019/07/03 Python
django 自定义过滤器(filter)处理较为复杂的变量方法
2019/08/12 Python
CSS3感应鼠标的背景闪烁和图片缩放动画效果
2014/05/14 HTML / CSS
印度最大的酒店品牌网络:OYO Rooms
2016/07/24 全球购物
德国家具折扣店:POCO
2020/02/28 全球购物
说说你所熟悉或听说过的j2ee中的几种常用模式?及对设计模式的一些看法
2012/05/24 面试题
介绍一下HDLC(High-Level Data Link Control)高层数据链路协议
2012/01/21 面试题
车间统计员岗位职责
2014/01/05 职场文书
个人委托书
2014/07/31 职场文书
我们的节日元宵节活动总结
2015/02/06 职场文书
大学生自荐信范文
2015/03/05 职场文书
毕业设计致谢词
2015/05/14 职场文书