`

PHP 引用是个坏习惯

    博客分类:
  • php
阅读更多

 

在写PHP 程序的时候,很多人在传递参数的时候,喜欢用一个引用。特别是在一个数组非常的大的时候,更是喜欢加。
复制代码代码如下:

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中关于引用(&)详解.docx

    php中关于引用(&)详解 php中关于引用(&)详解 php中关于引用(&)详解

    PHP的引用详解

    引用是什么 在 PHP 中引用意味着用不同的名字访问同一个变量内容。这并不像 C 的指针,替代的是,引用是符号表别名。注意在 PHP 中,变量名和变量内容是不一样的,因此同样的内容可以有不同的名字。最接近的比喻是 ...

    php 传值赋值与引用赋值的区别

    传值赋值:当将一个表达式的值赋予一个... 引用赋值:新的变量简单的引用了原始变量,改变新的变量将影响到原始变量使用引用赋值,简单地将一个&符号加到将要赋值的变量前(源变量) 类型戏法PHP 在变量定义中不需要

    腾讯PHP面试题_腾讯php面试题_

    最新腾讯PHP面试题1. php 的垃圾回收机制 PHP 可以自动进行内存管理,清除不需要的对象。 PHP 使用了引用计数 (reference ...当某个对象的引用计数器为零时,PHP 知道你将不再需要使用这个对象,释放其所占的内存空间。

    php中引用&的用法分析【变量引用,函数引用,对象引用】

    PHP 的引用允许你用两个变量来指向同一个内容 &lt;?php $a=ABC; $b =&$a; echo $a;//这里输出:ABC echo $b;//这里输出:ABC $b=EFG; echo $a;//这里$a的值变为EFG 所以输出EFG echo $b;//这里输出EFG ?&gt; 函数的...

    PHP 基础实例教程(PHP网页实例版)

    PHP变量自增/减与变量引用 PHP 比较操作符 PHP 逻辑操作符 PHP 三元操作符 PHP 错误抑制操作符 PHP 执行操作符 PHP 数组操作符 PHP 操作符综合使用 PHP 条件判断/循环 PHP if语句 PHP else语句 PHP elseif语句 PHP ...

    PHP面向对象编程的7个好习惯(1)

    PHP 面向对象编程的7个好 习惯(1)。

    一道关于php变量引用的面试题

    当一个变量等于另一个变量的引用的时候,这时任何一方改变了其值,另一方看到的这个值也会变化的。前加本次就表现出来,而后加下一次才会表现出来。 您可能感兴趣的文章:PHP中函数内引用全局变量的方法浅谈PHP变量...

    php引用返回与取消引用的详解

    一、引用返回引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用!要返回引用,使用此语法:复制代码 代码...

    PHP7扩展向PHP添加了SoftandWeak引用支持

    PHP 7扩展,向PHP添加了Soft and Weak引用支持

    PHP变量引用(&amp;)、函数引用和对象引用_.docx

    PHP变量引用(&amp;)、函数引用和对象引用_.docx

    php调用jar包依赖包

    php调用jar包依赖包

    提高php编程的50个习惯

    50个提高PHP编程效率的方法 0、用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数...

    PHP实现多个关键词搜索查询功能示例

    本文实例讲述了PHP实现多个关键词搜索查询功能。分享给大家供大家参考,具体如下: PHP对于数据库的搜索主要通过使用SQL语句中的like子句来实现。如果同时搜索多个关键词,可以使用union子句来将搜索结果合并起来。...

    PHP中文教程:PHP面向对象语法(构造函数、析构函数、引用)

    PHP面向对象语法 讲解了构造函数 析构函数 引用及引用传递

    PHP函数 -函数的高级用法.ppt

    * PHP函数 -----函数的高级用法 课程内容 可变函数 引用函数返回值 函数的嵌套调用 函数的递归调用 回调函数 一、可变函数 一个变量的值可以为另一个变量的名称。此外,一个变量的值还可以是一个函数的名称,这就是...

    PHP—引用文件.docx

    PHP—引用文件.docx

    php地址引用(php地址引用的效率问题)

    复制代码 代码如下: &lt;?php echo ‘begin time:’.$begin=microtime(false).' ’;//begin to count time $array=array();...//地址引用 时间总是控制在0.01之内 地址引用的优势体现出来了 forea

Global site tag (gtag.js) - Google Analytics