【變量存儲】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' }