• php引用使用不恰当而产生问题的地方


    php变量的引用,如果使用的恰当,会带来效率的提升,相反,效率下降

    $array = range(0, 1000000);
    $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=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

  • 相关阅读:
    Java9模块化(Jigsaw)初识
    Java9 modules (Jigsaw)模块化迁移
    Java数据库连接——JDBC调用存储过程,事务管理和高级应用
    面向对象编程(三)——程序执行过程中内存分析
    面向对象编程(十)——继承之Super关键字及内存分析
    面向对象编程(十二)——final关键字
    项目管理利器——Maven阅读目录
    深入分析Java的序列化与反序列化
    Java提高篇——Java 异常处理
    怎么运行Typescript
  • 原文地址:https://www.cnblogs.com/taek/p/5458067.html
Copyright © 2020-2023  润新知