PHP 引用是個壞習慣

2021-09-01 11:01:29 字數 2049 閱讀 5697

在寫php 程式的時候,很多人在傳遞引數的時候,喜歡用乙個引用。特別是在乙個陣列非常的大的時候,更是喜歡加。

複製****如下:

function binsearch(&$arr, $key, $value) 

else if ($value > $item) else  

} return false; 

} 在這裡,$mid 採用了先減後加的方法計算,目的是為了防止整數的溢位。不是故意寫複雜了。 

我用下面的**進行測試: 

複製****如下:

$data = array(); 

for ($i = 0; $i < 1000000; $i++)   

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 = 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 引用是個壞習慣

在寫php 程式的時候,很多人在傳遞引數的時候,喜歡用乙個引用。特別是在乙個陣列非常的大的時候,更是喜歡加。function binsearch arr key value elseif value item else return false 在這裡,mid 採用了先減後加的方法計算,目的是為了防...

PHP 引用是個壞習慣

這篇文章,寫的比較早,有一些錯誤的說法,我表示非常歉意。一些 沒有經過嚴格的測試,以後寫部落格一定要非常謹慎。因為可能會對一些人產生誤導。在寫php 程式的時候,很多人在傳遞引數的時候,喜歡用乙個引用。特別是在乙個陣列非常的大的時候,更是喜歡加。function binsearch arr key ...

PHP 引用是個壞習慣

這篇文章,寫的比較早,有一些錯誤的說法,我表示非常歉意。一些 沒有經過嚴格的測試,以後寫部落格一定要非常謹慎。因為可能會對一些人產生誤導。在寫php 程式的時候,很多人在傳遞引數的時候,喜歡用乙個引用。特別是在乙個陣列非常的大的時候,更是喜歡加。function binsearch arr key ...