Может ли кто-нибудь объяснить мне, почему передача переменных по ссылкам ведет себя так, как я наблюдаю?
Вот метод из контроллера, над которым я работаю:
public function view($view,$context=array()){
// <snip>
foreach($context as $a=>$b){
$$a = $b;
}
// <snip>
}
Копирует данные $context
массив в локальной области видимости, так что когда представление вызывается (включается), он может получить доступ к элементам.
$foo->method(); // first thing
$bar->method(); // second thing
Будучи немного суетливым, я хотел работать с реальными объектами, а не с копиями (что казалось просто расточительным), поэтому я изменил это на следующее:
public function view($view,$context=array()){
// <snip>
foreach($context as $a=>$b){
$$a =& $b;
}
// <snip>
}
Именно тогда я стал свидетелем чего-то, чего я не ожидал.
$foo->method(); // second thing!!
$bar->method(); // second thing
В тестовом примере два объекта передаются в представление, которое затем выводит соответствующие данные. При передаче по ссылке, а не по значению обе переменные заканчивались ссылками на второй объект.
Я не ожидал, что это произойдет. Я бы очень хотел, чтобы кто-то объяснил мне, почему это произошло. Я, вероятно, пропустил что-то очевидное, поэтому, пожалуйста, просветите меня.
В случае, если это уместно (я подозреваю, что это может быть, но я не уверен).
Метод вызывается так:
$data = array();
$data['foo'] =& $this->module()->get_foo();
$data['bar'] =& $this->module()->get_bar();
$this->view('nameOfView',$data);
В этом случае по возвращаемой ссылке возвращается & здесь, наверное, перебор. Опять же, я не так уверен, как хотелось бы. Для целей этого вопроса я просто действительно Я хочу понять, что происходит с перезаписью ссылок в методе view, но не стесняйтесь учить меня чему-то еще, что я должен знать, но явно не знаю.
Потому что переменная $b
используется повторно foreach
петля.
И в качестве $b
переназначен, так же как и все ссылки на него.
Простой пример:
$a = [1, 2, 3];
$c = [];
foreach($a as $b)
{
$c[] = &$b;
}
print_r($c);
Который дает:
Array
(
[0] => 3
[1] => 3
[2] => 3
)
Вы даже можете сделать шаг вперед и выполнить задание после foreach
цикл:
$b = 'derp';
который превратит ваш массив в это:
Array
(
[0] => derp
[1] => derp
[2] => derp
)
Теперь, как уже дважды отмечалось в комментариях, есть функция extract()
, который, кажется, был сделан именно для того, что вы пытаетесь сделать, и именно так я и предлагаю.
Но ради полноты достаточно просто «исправить» ваш код.
Есть два способа сделать это:
Делать $b
ссылка вместо копии.
Вы можете сделать это с помощью $a as &$b
в качестве аргумента foreach
:
$a = [1, 2, 3];
$c = [];
foreach($a as &$b)
{
$c[] = &$b;
}
print_r($c);
Сломать ссылку на $b
до того, как он переназначен.
Вы можете сделать это, позвонив unset($b);
в конце вашего цикла:
$a = [1, 2, 3];
$c = [];
foreach($a as $b)
{
$c[] = &$b;
unset($b);
}
print_r($c);
Оба из вышеперечисленного дадут вам то, что вы изначально ожидали:
Array
(
[0] => 1
[1] => 2
[2] => 3
)
Обратите внимание, что при использовании первого способа и вы изменяете $a
после этого, $c
может измениться, но не всегда.
Например, прямое назначение ($a[0] = 5;
) повлияет $c
($c[0] == 5
).
$c
остается незатронутым любым другим действием на $a
(насколько я могу судить), но после возни с индексами в $a
(как с array_shift()
или же shuffle()
), $c[1]
может быть ссылкой на $a[0]
, так далее.
Если ты не хочешь головной боли, просто иди с extract()
,
Других решений пока нет …