PHP变量存储与赋值

【变量存储】php

php变量保存在一个叫zval的变量容器中。zval变量容器是在变量赋值时建立的;
zval变量容器除了包含变量的类型和值,还包括两个字节的额外信息:数组

  • 第一个字节是‘is_ref’,BOOL值,标识变量是否属于引用集合(reference set)。php引擎经过该字节区分普通变量和引用变量;
  • 第二个字节是‘refcount’,表示指向该zval变量容器的标识(symbol)的个数。全部的标识都存放在一个标识表中,其中每一个标识都有各自的做用域。当变量离开其做用域或对变量调用unset()时,其对应的refcount就会减1,当refcount变成0时,该zval容器将被销毁;
 1 //因为zvalue用来存放变量的实际数据,切要存放多种类型,因此经过union实现PHP的若类型
 2 type union _zvalue_value{
 3     long lval;    //long value
 4     double dval;    //double value
 5     struct{
 6         char *val;
 7         int len;
 8     }str;    //string value
 9     HashTable *ht;    //hash table value
10     zend_object_value obj;
11 } zvalue_value;
12 
13 //Variable information
14 struct _zval_struct{
15     zvalue_value value;    //value
16     zend_unit refcount;
17     zend_uchar type;    //active type
18     zend_uchar is_ref;
19 }
20 
21 typedef struct _zval_strct zval;
22 /*
23     type值与实际类型的对应关系:
24     IS_LONG -> lvalue;
25     IS_DOUBLE -> dvalue;
26     IS_ARRAY -> ht;
27     IS_STRING -> str;
28     IS_RESOURCE -> lvalue
29 
30     is_ref和refcount:用于实现引用计数;    
31 */
zval的数据结构

 

【查看变量信息】数据结构

前提ide

配置Xdebug(参考PHP经常使用配置)后,能够经过xdebug_debug_zval()函数查看变量信息;函数

 1 //查看php加载的全部Zent扩展
 2 print_r(get_loaded_extensions(true));
 3 //显示结果
 4 Array
 5 (
 6     [0] => Xdebug
 7 )
 8 
 9 //查看xdebug扩展的全部函数
10 print_r(get_extension_funcs('xdebug'));
11 //运行结果
12 Array
13 (
14     [0] => xdebug_get_stack_depth
15     [1] => xdebug_get_function_stack
16     [2] => xdebug_get_formatted_function_stack
17     [3] => xdebug_print_function_stack
18     [4] => xdebug_get_declared_vars
19     [5] => xdebug_call_class
20     [6] => xdebug_call_function
21     [7] => xdebug_call_file
22     [8] => xdebug_call_line
23     [9] => xdebug_var_dump
24     [10] => xdebug_debug_zval
25     [11] => xdebug_debug_zval_stdout
26     [12] => xdebug_enable
27     [13] => xdebug_disable
28     [14] => xdebug_is_enabled
29     [15] => xdebug_break
30     [16] => xdebug_start_trace
31     [17] => xdebug_stop_trace
32     [18] => xdebug_get_tracefile_name
33     [19] => xdebug_get_profiler_filename
34     [20] => xdebug_dump_aggr_profiling_data
35     [21] => xdebug_clear_aggr_profiling_data
36     [22] => xdebug_memory_usage
37     [23] => xdebug_peak_memory_usage
38     [24] => xdebug_time_index
39     [25] => xdebug_start_error_collection
40     [26] => xdebug_stop_error_collection
41     [27] => xdebug_get_collected_errors
42     [28] => xdebug_start_code_coverage
43     [29] => xdebug_stop_code_coverage
44     [30] => xdebug_get_code_coverage
45     [31] => xdebug_get_function_count
46     [32] => xdebug_dump_superglobals
47     [33] => xdebug_get_headers
48 )
查看是否加载Xdebug扩展及Xdebug相关函数

【查看简单类型的变量】this

 1 //设置变量$a
 2 $a='new string';
 3 //显示$a相关信息
 4 xdebug_debug_zval('a');
 5 //运行结果
 6 a: (refcount=1, is_ref=0)='new string'
 7 
 8 //赋值NULL
 9 $a=null;
10 xdebug_debug_zval('a');
11 //运行结果
12 a: (refcount=1, is_ref=0)=NULL
13 
14 //unset()
15 unset($a);
16 xdebug_debug_zval('a');
17 //unset()后将消除zval容器,运行结果为空

【查看复合类型的变量】spa

复合类型的变量存储与简单类型不太同样。Array和Object类型的变量将其成员或属性保存在本身的标识表中。这意味着,一个复合类型的变量将建立多个zval容器。debug

 1 //显示数组信息
 2 $ary=array('name'=>'SM');
 3 xdebug_debug_zval('ary');
 4 //运行结果:ary: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='SM')
 5 
 6 $ary['reName']=$ary['name'];
 7 xdebug_debug_zval('ary');
 8 //运行结果:ary: (refcount=1, is_ref=0)=array ('name' => (refcount=2, is_ref=0)='SM', 'reName' => (refcount=2, is_ref=0)='SM')
 9 
10 $ary['self']=$ary;
11 xdebug_debug_zval('ary');
12 //运行结果(注意$ary和$ary['self']的refcount都是1):ary: (refcount=1, is_ref=0)=array ('name' => (refcount=4, is_ref=0)='SM', 'reName' => (refcount=4, is_ref=0)='SM', 'self' => (refcount=1, is_ref=0)=array ('name' => (refcount=4, is_ref=0)='SM', 'reName' => (refcount=4, is_ref=0)='SM'))
13 
14 unset($ary['reName']);
15 xdebug_debug_zval('ary');
16 //运行结果(注意$ary['self']):ary: (refcount=1, is_ref=0)=array ('name' => (refcount=3, is_ref=0)='SM', 'self' => (refcount=1, is_ref=0)=array ('name' => (refcount=3, is_ref=0)='SM', 'reName' => (refcount=3, is_ref=0)='SM'))

 

【变量赋值】3d

【传值赋值】code

 1 //建立变量并赋值
 2 $a='string a';
 3 //建立zval容器保存字符串'string a'及其它相关信息。而且,系统产生一个惟一标识(在此记为IdA)指向该zval容器。变量名$a的存储单元所保存的内容是指向该zval容器的IdA。
 4 //查看$a相关信息
 5 xdebug_debug_zval('a');
 6 //运行结果
 7 a: (refcount=1, is_ref=0)='string a'    //只有$a保存IdA,因此'string a'的refcount=1
 8 
 9 //传值赋值
10 $b=$a;
11 //赋值后,将$a所保存的信息(IdA)复制到$b的存储单元中。此时,$a和$b存储单元中的内容都是IdA。
12 //查看$a和$b相关信息
13 xdebug_debug_zval('a');
14 xdebug_debug_zval('b);
15 //运行结果
16 a: (refcount=2, is_ref=0)='string a'    //$a和$b都保存IdA,因此'string a'的refcount=2
17 b: (refcount=2, is_ref=0)='string a'
18 
19 //建立$c并赋值给$b
20 $c='string c';
21 //此时将建立新的zval容器保存’string c'及其相关信息,并产生惟一标识(在此记为IdC)指向该zval容器。$c所分配的存储单元保存的信息即为IdC22 $b=$c;
23 //赋值过程是将$c存储单元中的IdC复制到$b的存储单元中。此时,$b保存的信息是IdC,而$a所保存的的信息仍然是IdA。
24 //查看$a,$b,$c
25 xdebug_debug_zval('a');
26 xdebug_debug_zval('b');
27 xdebug_debug_zval('c');
28 //运行结果
29 a: (refcount=1, is_ref=0)='string a'    //只有$a保存IdA,因此'string a'的refcount=1
30 b: (refcount=2, is_ref=0)='string c'    //$b和$c都保存IdC,因此'string c'的refcount=2
31 c: (refcount=2, is_ref=0)='string c'
32 
33 //为$b从新赋值
34 $b='string b';
35 //建立新的zval容器保存’string b'及其它相关信息,并产生惟一标识(在此记为IdB)指向该zval容器。此时$b存储希望所保存的信息即为IdB。
36 //查看$a,$b,$c
37 xdebug_debug_zval('a');
38 xdebug_debug_zval('b');
39 xdebug_debug_zva('c');
40 //运行结果
41 a: (refcount=1, is_ref=0)='string a'    //只有$a保存IdA,因此'string a'的refcount=1
42 b: (refcount=1, is_ref=0)='string b'    //只有$b保存IdB,因此'string b'的refcount=1
43 c: (refcount=1, is_ref=0)='string c'    //只有$c保存IdC,因此'string c'的refcount=1

【引用赋值】

 1 //建立变量$a
 2 $a='string a';
 3 //显示$a相关信息
 4 xdebug_debug_zval('a');
 5 //运行结果
 6 a: (refcount=1, is_ref=0)='string a'
 7 
 8 //$a引用赋值给$b
 9 $b=&$a;
10 //显示$a,$b
11 xdebug_debug_zval('a');
12 xdebug_debug_zval('b');
13 //运行结果
14 a: (refcount=2, is_ref=1)='string a'
15 b: (refcount=2, is_ref=1)='string a'
16 
17 //$a传值赋值给$c
18 $c=$a
19 //显示$a,$b,$c
20 xdebug_debug_zval('a');
21 xdebug_debug_zval('b');
22 xdebug_debug_zval('c');
23 //运行结果
24 a: (refcount=2, is_ref=1)='string a'
25 b: (refcount=2, is_ref=1)='string a'
26 c: (refcount=1, is_ref=0)='string a'

【对象操做】

 1 class Persion {
 2     public $name='SM';
 3     public function GetName() {
 4     Return $this->name;
 5     }
 6 }
 7 
 8 $psn=new Persion;
 9 xdebug_debug_zval('psn');
10 //运行结果
11 //psn: (refcount=1, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
12 
13 $psn1=$psn;
14 xdebug_debug_zval('psn');
15 xdebug_debug_zval('psn1');
16 //运行结果
17 //psn: (refcount=2, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
18 //psn1: (refcount=2, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
19 
20 $psn2=&$psn;
21 xdebug_debug_zval('psn');
22 xdebug_debug_zval('psn1');
23 xdebug_debug_zval('psn2');
24 //运行结果
25 //psn: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
26 //psn1: (refcount=1, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
27 //psn2: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
28 
29 $psn1->name='SMS';
30 xdebug_debug_zval('psn');
31 xdebug_debug_zval('psn1');
32 xdebug_debug_zval('psn2');
33 //运行结果(注意$spn,$spn1,$spn2的name属性值都是'SMS')
34 //psn: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SMS' }
35 //psn1: (refcount=1, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SMS' }
36 //psn2: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SMS' }
相关文章
相关标签/搜索