ホームページ >バックエンド開発 >PHPチュートリアル >php引用传参 - php函数引用传参数组:function set(array &$array, $path, $value)
<code>function set(array &$array, $path, $value) { print_r($array); echo('<br> <hr> '); $segments = explode('.', $path); while(count($segments) > 1) { $segment = array_shift($segments); if(!isset($array[$segment]) || !is_array($array[$segment])) { $array[$segment] = []; } $array =& $array[$segment]; print_r($array); echo('<br><hr>'); } $array[array_shift($segments)] = $value; print_r($array); echo('<br><hr>'); } $arr = ['a' => 1, 'b' => 2, 'c' => 3]; set($arr, 'a.b.d', 4); print_r($arr); </code>
结果:
为什么最终结果不是Array ( [d] => 4 ),而是 Array ( [a] => Array ( [b] => Array ( [d] => 4 ) ) [b] => 2 [c] => 3 ) ?
这个怎么解: $array =& $array[$segment];
<code>function set(array &$array, $path, $value) { print_r($array); echo('<br> <hr> '); $segments = explode('.', $path); while(count($segments) > 1) { $segment = array_shift($segments); if(!isset($array[$segment]) || !is_array($array[$segment])) { $array[$segment] = []; } $array =& $array[$segment]; print_r($array); echo('<br><hr>'); } $array[array_shift($segments)] = $value; print_r($array); echo('<br><hr>'); } $arr = ['a' => 1, 'b' => 2, 'c' => 3]; set($arr, 'a.b.d', 4); print_r($arr); </code>
结果:
为什么最终结果不是Array ( [d] => 4 ),而是 Array ( [a] => Array ( [b] => Array ( [d] => 4 ) ) [b] => 2 [c] => 3 ) ?
这个怎么解: $array =& $array[$segment];
首先,如果语句$array =& $array[$segment]
中的&
符号去掉,结果就如楼主所期待的最后输出Array([d] => 4)
。显然问题的关键就在那一句的&
上面。
我们知道php
在存储变量和变量的值时分别用了两种数据结构zval
和zval_value
。在zval
中包含四个字段:refcount_gc
表示引用计数is_ref_gc
表示是否为引用value
存储变量标识符type
变量的具体类型
变量的实际值存储在另一个联合体中,具体结构省略。现在我们来模拟一下过程:
首先$arr = ['a' => 1, 'b' => 2,'c' => 3]
创建:arr{'refcount_gc':1, 'is_ref_gc':0,'value':'arr','type':array}
(后面将会省略value和type的书写),同时创建array类型的zval_value。['a']{'refcount_gc':1, 'is_ref_gc':0, ...}
['b']{'refcount_gc':1, 'is_ref_gc':0, ...}
['c']{'refcount_gc':1, 'is_ref_gc':0, ...}
在调用set
方法时,传递的是$arr
的一个引用:&arr{'refcount_gc':2, 'is_ref_gc':1, ...}
接着进入函数体,while
循环内,第一次由于!is_array($arr['a'])
成立,为$arr['a']
赋值空数组。['a']{'refcount_gc':1, 'is_ref_gc':0, ...}
,并创建类型为array的zval_value。$arr =& $arr['a'];
这一句又将原数组的['a']
转为引用['a']:{'refcount_gc':2, 'is_ref_gc':1, ...}
,它和arr
都同时是这个空数组的引用①。
接着第二次循环,由于此时arr是一个空数组的引用,!isset($arr['b'])
成立,为$arr['b']
赋值空数组。arr['b']{'refcount_gc':2, 'is_ref_gc':1, ...}
,并创建类型为array的zval_value,同时由于①,原来数组的['a']
也是这个空数组的引用, 也就是在原数组['a']
基础上有了['a']['b']
②。$arr =& $arr['b'];
这一句又将arr['b']
转为引用arr['b']:{'refcount_gc':3, 'is_ref_gc':1, ...}
,由于②,①中的空数组的['b']
,原数组的['a']['b']
和arr都同时是这个空数组的引用③。
然后退出循环。$arr['d'] = 4;
为②中的空数组创建索引['d']
,且由于③,原数组的['a']['b']
、①中数组的['b']
也是这个数组的引用,他们都指向了这个(['d'] => 4)
的数组。
所以最后打印原数组出来的就是Array ( [a] => Array ( [b] => Array ( [d] => 4 ) ) [b] => 2 [c] => 3 )
简化的图示为:
画的比较随意。。大致按数字步骤体现其过程。。。
问题主要出现在
<code> while(count($segments) > 1) { $segment = array_shift($segments); if(!isset($array[$segment]) || !is_array($array[$segment])) { $array[$segment] = []; } //这里传引用赋值,将$array[$segment]的引用传给了$array //所以此后的$array已经不再指向传参近来的那个$array(但传参进来的那个$array并未消失) //最简单的方法是将这个&去掉,在输出一遍,你应该就明白了 $array =& $array[$segment]; print_r($array); echo('<br><hr>'); } </code>
运行一下,如果不明白有问题可以留言