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' }
相關文章
相關標籤/搜索