php变量的引用,如果使用的恰当,会带来效率的提升,相反,效率下降
$array = range(, );
$ref =& $array;
var_dump(count($array)); //
count是个内置函数,参数只接收传值,但现在传入的参数$array是个引用,由于在php5中,某个值是不能引用变量和非引用变量之间使用,
针对这个例子来说,即在count内部,php引擎会copy一个$arrray指向的zval,所以效率就降下来了
如果传的count的参数不是引用,那么count内部不会做copy动作, 在copy内部,接收的参数其实也会指向 $array指向的zval,因为php数组的名称就代表了在内存的地址
$a="123";
$b=$a; // $a,$b 指向同一个zval_1, type=IS_STRING, refcount_gc=2, is_ref_gc=0
$c=&$b; //由于同一值(zval)不能被引用变量和非引用变量之间使用,要分离 , $c, $d指向zval_2 type=IS_STRING, refcount_gc=2, is_ref_gc=1
$d=$c //如上也要分离,尽管$d的值没有重新赋值 $d 指向zval_3,type=IS_STRING, ref_count_gc=1,is_ref_gc=0
在php7中,某个值是可能在引用变量和非引用变量之间使用的,只有当发生变化时,才会copy一份zval
$c=&$b; 因为有$c,$d两个变量 zval.value.ref->gc.refcount=2 zval.value.ref->val.value.str.gc.refcount=2 ($a,$b)
$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=;
} $a=;
test($a);
$a的值为2
如果说
function test($b){ $b=; } $a=; 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