php引用使用不恰當而產生問題的地方

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

相關文章
相關標籤/搜索