TL; DR Для вашего случая вы можете рассмотреть возможность использования оператора null coalesce следующим образом:
$a = $a ?? [];
foreach ($a as &$v) { ... }
Или вообще не использовать ссылки, используя либо array_map()
или с помощью ключей для внесения изменений в базовый массив.
Q1
$a = [1, 2];
foreach ($a ?? [] as &$v) {
$v++;
}
var_dump($a);
Оператор coalesce использует копию исходного массива, а затем применяет правый операнд если null
. Следовательно, итерация выполняется для копии исходного массива.
Вы можете сравнить это со следующим:
$a = [1, 2];
$x = $a ?? [];
$x[1] = 4;
var_dump($a); // [1, 2]
Code Insight
compiled vars: !0 = $a, !1 = $v
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
8 0 E > ASSIGN !0, <array>
9 1 COALESCE ~3 !0
2 QM_ASSIGN ~3 <array>
3 > FE_RESET_RW $4 ~3, ->8
... rest of looping code
Первый операнд FE_RESET_RW
- это переменная ha sh, которая будет перебираться, и вы можете видеть, что она ~3
вместо !0
($a
в вашем коде), что вы и ожидали.
Q2
foreach ($a = [1, 2] as &$v) {
$v++;
}
Здесь происходит то, что возвращаемое значение присваивания $a = [1, 2]
используется в качестве массива для итерации.
Вы можете сравнить это поведение с чем-то как это:
$x = $a = [1, 2];
$x[0] = 4; // modify in-place
var_dump($a); // [1, 2]
Code Insight
compiled vars: !0 = $a, !1 = $v
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
3 0 E > ASSIGN $2 !0, <array>
1 > FE_RESET_RW $3 $2, ->6
... rest of looping code
Опять же, $2
- это первый операнд FE_RESET_RW
, который является результатом присваивания, и поэтому итерация не произойдет с !0
($a
в вашем коде).