php變量的引用,若是使用的恰當,會帶來效率的提高,相反,效率降低php
$array = range(0, 1000000); $ref =& $array; var_dump(count($array)); //
count是個內置函數,參數只接收傳值,但如今傳入的參數$array是個引用,因爲在php5中,某個值是不能引用變量和非引用變量之間使用,node
針對這個例子來講,即在count內部,php引擎會copy一個$arrray指向的zval,因此效率就降下來了數組
若是傳的count的參數不是引用,那麼count內部不會作copy動做, 在copy內部,接收的參數其實也會指向 $array指向的zval,由於php數組的名稱就表明了在內存的地址php7
$a="123";函數
$b=$a; // $a,$b 指向同一個zval_1, type=IS_STRING, refcount_gc=2, is_ref_gc=0ui
$c=&$b; //因爲同一值(zval)不能被引用變量和非引用變量之間使用,要分離 , $c, $d指向zval_2 type=IS_STRING, refcount_gc=2, is_ref_gc=1spa
$d=$c //如上也要分離,儘管$d的值沒有從新賦值 $d 指向zval_3,type=IS_STRING, ref_count_gc=1,is_ref_gc=0指針
在php7中,某個值是可能在引用變量和非引用變量之間使用的,只有當發生變化時,纔會copy一份zvalcode
$c=&$b; 由於有$c,$d兩個變量 zval.value.ref->gc.refcount=2 zval.value.ref->val.value.str.gc.refcount=2 ($a,$b)blog
$d=$c zval.value.ref->val.value.str.gc.refcount=3 ($a,$b ,$d)
struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* call info for EX(This) */ } v; uint32_t type_info; } u1; union { uint32_t var_flags; uint32_t next; /* hash collision chain */ uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ } u2; }; typedef union _zend_value { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww; } zend_value;
struct _zend_refcounted { zend_refcounted_h gc; }; typedef struct _zend_refcounted_h { uint32_t refcount; /* reference counter 32-bit */ union { struct { ZEND_ENDIAN_LOHI_3( zend_uchar type, zend_uchar flags, /* used for strings & objects */ uint16_t gc_info) /* keeps GC root number (or 0) and color */ } v; uint32_t type_info; } u; } zend_refcounted_h;
因此說php當初被髮明出來,是爲了更方便使用者, 這樣的結果就是使用方能夠隨意寫代碼,但php引擎就要作大量的維護工做
那麼php的參數是如何運行的?
function test(&$b){ $b=2; } $a=1; test($a);
$a的值爲2
若是說
function test($b){ $b=2; } $a=1; test($a);
$a的結果是1
由於咱們形參是實參的一個拷貝,對拷貝的操做不會影響到實參
$a=1;
首先分配一個zval*的內存,填充zval中的value(zva.value.lval=1)以及type(zva.type=IS_LONG)
而後放到active_symbol_table這個hashTable中, key爲'a' value爲一個zval指針,該指針指向上面的zval
$a="abc"
經過zend_hash_quick_get(EG(active_symbol_table),'a', ptr) 獲得key爲'a' 的對應的value的內存地址,即上面zval的地址,再設置其zval.value.str.val="abc";
$a=2;
經過zend_hash_quick_get(EG(active_symbol_table),'a', ptr) 獲得key爲'a' 的對應的value的內存地址,即上面zval的地址,
由於此時zval的類型爲IS_STRING,故要釋放到zva.value.str這段內存
再設置其zval.value.lval=2;
$b=$a;
首先zend_hash_quick_get(EG(active_symbol_table),'a')獲得變量a 對應的zval的地址
而後zend_hash_quick_set(EG(active_symbol_table),'b', 上面zval對應的地址);
$c=&$b
分離zval, 再次分配一個zval類型的內存,copy value和type,初始爲refcount_gc以及is_ref_gc
zend_hash_quick_set(EG(active_symbol_table),'b', 新的zval對應的地址);
zend_hash_quick_set(EG(active_symbol_table),'c', 新的zval對應的地址);
$c=5;
zend_hash_quick_get(EG(active_symbol_table),'c')獲得變量c 對應的zval的地址
zval.value.lval=5