Здесь есть две вещи. Код написан довольно интересным способом, хотя и сложным для понимания.
Как вы поняли, да при каждом взаимодействии $$v
будет переводить в переменные соответственно $2, $3, $3, $1, $5, $2
.
PHP довольно гибок (возможно, даже слишком много ), поэтому позволяет * проверять if ($2)
, даже если $2
явно никогда не создавался ранее. Он принимает NULL
в качестве значения, поэтому проверка if не проходит.
* «Примечание: неопределенная переменная: $ 2» будет добавлена в журналы, но это не «нарушает» код и не препятствует его выполнению.
Очень важно понимать разницу между преинкрементом и постинкрементом.
$a = 0;
$b = 0;
($a++ === 1) // FALSE
(++$b === 1) // TRUE
Предварительное увеличение добавляет к переменной и затем возвращает ее (новое, добавленное) значение; Тогда как постинкремент возвращает текущее значение переменной и только потом добавляет к нему.
Объединение обоих
Для удобства чтения давайте переведем эту строку
if ($$v++) return $v;
в
if ($$v) {
return $v;
}
$$v = $$v + 1;
поскольку это то, что действительно происходит.
Переход к второй итерации (первая 3
в массиве, где $v = 3
, мы бы получили:
// Right now $3 doesn't exist, so it's value is NULL
if ($3) { // "if (NULL)", so it's FALSE
return 3;
}
$3 = $3 + 1; // "NULL + 1"
// $3 === 1 at this point
Почему PHP компилирует NULL + 1
= 1
Это совсем другая тема («слишком гибкая», помните?). В итоге предполагается, что NULL
числовое значение равно 0
, поэтому 0 + 1 = 1
анализируется.
Теперь, когда дело доходит до третьей итерации (вторая 3
в массиве, где $v = 3
снова - , но в это время переменная $3
существует, и ее значение равно 1
)
// Right now: $3 === 1
if ($3) { // TRUE
return 3;
}
$3 = $3 + 1; // This line is never reached, the code has "returned" already
Вот и все, надеюсь, это несколько легко понять. Это много разных частей, которые должны быть объединены, чтобы иметь смысл.