小小見解(參考風雪之隅及網上相關資料):
引用和複製的區別:
大家都知道引用其實就是:$a = 1;$b = $a;改變$a或者$b不會影響對方。而引用是按地址傳值:$a = 1;$b = &$a;改變任何一個另一個值都會改變。
但是在末尾加個why呢,為什麼會是這樣呢?
大家需要理解php裡面的兩個機制就是copy on write 和 change on write:
copy on write :寫時複製;應用於變數複製。例如上面例子,$a = 1;$a變數存放在符號表裡面,而值"1"存放在zval中。意思也就是說php裡面存放
的變數,每個變數名都存放在符號表裡面,每個符號對應一個zval;zval可以看做一個容器,裡面存放著變數值,變數類型,等等。
$a = 1;$b = $a;可能會有人認為記憶體裡有兩個"1",實際上並不是這樣的,$a與$b都指向存放1的zval容器。可以形象比喻為,$a與$b各自有條線指向
zval,zval中有個參數是refcount來計數的,就是統計有多少線指向自己的。當有個變數進行複製時候refcount就會加1。即:$a = 1;$b = $a;此時存
放1的zval結構裡面的refcount值為2。php裡面有個函數可以查看,就是debug_zval_dump($v);當debug_zval_dump($a);時候計數為3,因為$a是以
傳值得形式傳給debug_zval_dump的所以列印出來的值是3。
接著說明一個問題,就是unset,它的作用是使變數的refcount數減一。也就是當refcount值為0的時候才會將變數值占的記憶體釋放掉。當unset($b)的時候
1並沒有在記憶體中釋放掉,而是指向它的引用數減。
當中說到的記憶體釋可能並不會釋放給系統(OS),php會為自己開闢個指定大小的記憶體,當有變數產生時候會去自己的記憶體區裡面申請,當釋放的時候會釋放到自
己的記憶體地區裡面。對於提高效率有很大協助了。但是當超出這個指定值得時候會去向系統申請記憶體了,那時候再釋放的時候就會釋放給系統了
關於引用,zval裡面有另一個參數is_ref來標記(標記是否為真正的引用),此值預設為0,例如:$a = 1;$b = &$a;此時debug_zval_dump($a);結果為1,
refcount = 2,is_ref = 3,
版本5.2.17源碼中的zval聯合體,可以去官網下載
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount;
zend_uchar type; /* active type */
zend_uchar is_ref;
};
測試幾個程式的執行速度
測試環境:
OS:win7
php vesion 5.2.9
apache2.0
1.判斷變數值是否為空白用'!'加變數名字與empty加變數名做執行時間對比(迴圈1千萬次)
if裡面使用!$a執行時間為:2.40036678314s
if裡面使用empty($a)執行時間為:2.52875089645s
測試代碼:
$start = microtime(true);
$a = '';
for($i=0; $i < 10000000; $i++){
if(!$a){//可改為empty($a)
echo " ";
}
}
$end = microtime(true);
echo "執行時間為:",($end-$start),"s";
?>
2.使用if-esle與使用三元運算子做執行時間對比(迴圈1千萬次)
使用if-else 執行時間為:2.37516283989s
使用三元運算子 執行時間為:2.14390015602s
三元運算子運行時候,每次變數都會複製一次
if-else不會,影響甚微,只是拿出來和大家分享下
測試代碼:
$start = microtime(true);
$a = range(1, 1000);
for($i=0; $i < 10000000; $i++){
if(isset($a)){
echo " ";
}else{
echo "";
}
}
$end = microtime(true);
echo "執行時間為:",($end-$start),"s";
?>
$start = microtime(true);
$a = range(1, 1000);
for($i=0; $i < 10000000; $i++){
isset($a) ? " " : "";
}
$end = microtime(true);
echo "執行時間為:",($end-$start),"s";
?>