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