#php #arrays #global-variables
#php #массивы #глобальные переменные
Вопрос:
$GLOBALS["items"] = array('one', 'two', 'three', 'four', 'five' ,'six', 'seven');
$alter = amp;$GLOBALS["items"]; // Comment this line
foreach($GLOBALS["items"] as $item) {
echo get_item_id();
}
function get_item_id(){
var_dump(key($GLOBALS["items"]));
}
Проверьте вывод этого кода с закомментированной и раскомментированной второй строкой.
Мой результат (PHP 5.3.0).
Со второй строкой
int(1) int(2) int(3) int(4) int(5) int(6) NULL
Без второй строки:
int(1) int(1) int(1) int(1) int(1) int(1) int(1)
Почему такой странный результат?
Комментарии:
1. Я честен.. Понятия не имею.. получение указателя на $ GLOBALS не должно изменять переменную.
2. Хороший взлом. По-видимому, $ alter берет на себя управление. Если вы установите значение $alter равным NULL после присвоения массива, массив даже станет недействительным и вызовет ошибку в следующем цикле.
3. Возможно, это как-то связано с тем фактом, что
$GLOBALS
сам по себе является массивом ссылок. А ссылки в PHP всегда обалденные.4. @BoltClock, ты можешь заменить $ GLOBALS на другую переменную массива, и этот хак тоже работает )))
5. Я не понимаю, почему это должно быть «взломом». В чем преимущество? Имо, это либо ошибка, либо странное поведение, либо его можно объяснить.
Ответ №1:
Вот возможное объяснение:
Мы знаем, что foreach
всегда выполняется цикл над копией массива, если на него нет ссылки:
Если на массив нет ссылки,
foreach
работает с копией указанного массива, а не с самим массивом.foreach
имеет некоторые побочные эффекты для указателя на массив.
Это означает, что внутренний указатель исходного массива не изменен и key()
всегда будет возвращать одно и то же значение (как мы можем видеть, когда закомментируем строку). И действительно, если мы сделаем var_dump($GLOBALS)
, мы получим:
["items"]=>
array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
(ссылки нет)
Но как только мы генерируем ссылку на массив (с помощью $alter
), $GLOBALS['items']
ссылка тоже становится ссылкой, потому что обе записи должны указывать на один и тот же массив:
["items"]=>
amp;array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
["alter"]=>
amp;array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
Следовательно, foreach
цикл выполняет итерацию по исходному массиву и изменяет внутренний указатель, что влияет key()
.
Подводя итог: это проблема со ссылками, а не с $GLOBALS
.
Комментарии:
1. 1 Я представляю какого-нибудь бедолагу, который пытается изменить значения этого скопированного массива в цикле foreach.