【变量存储】php
php变量保存在一个叫zval的变量容器中。zval变量容器是在变量赋值时建立的;
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 */
【查看变量信息】数据结构
【前提】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 )
【查看简单类型的变量】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所分配的存储单元保存的信息即为IdC。 22 $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' }