Есть функция:
<?php
function test(){
static $count = 0;
$count++;
echo $count;
if ($count < 10) {
test();
}
$count--;
echo $count;
}
test();
?>
Этот код производит: 123456789109876543210
Когда $ count увеличивается до 10 — это понятно, он работает до тех пор, пока оператор не оценивается как false.
но почему оно постепенно уменьшается до 0?
В моей логике новичка $ count— в этом коде должен только уменьшиться до 9 один раз, и функция должна остановиться.
Не существует цикла или цикла, который может постепенно уменьшать его значение. Но мы видим, что это здесь и работает.
Почему так происходит?
Возможно, все становится немного яснее, когда вы меняете вывод, подчеркивая, как работает условный рекурсивный вызов:
<?php
function test($level=0) {
static $count = 0;
$count++;
echo str_pad('a:', $level+2, ' ', STR_PAD_LEFT), $count, PHP_EOL;
if ($count < 10) {
test($level+1);
}
$count--;
echo str_pad('b:', $level+2, ' ', STR_PAD_LEFT), $count, PHP_EOL;
}
test();
печать
a:1
a:2
a:3
a:4
a:5
a:6
a:7
a:8
a:9
a:10
b:9
b:8
b:7
b:6
b:5
b:4
b:3
b:2
b:1
b:0
Кажется, ваша проблема заключается в понимании того, как работают вызов (ы) функции и последующий возврат (ы) из функции. Давайте начнем с простого
<?php
function c() {
echo 'c in', PHP_EOL;
echo 'c out', PHP_EOL;
}
function b() {
echo 'b in', PHP_EOL;
c();
echo 'b out', PHP_EOL;
}
function a() {
echo 'a in', PHP_EOL;
b();
echo 'a out', PHP_EOL;
}
a();
печать
a in
b in
c in
c out
b out
a out
Легко, не правда ли? Когда функция выходит / возвращается, выполнение продолжается в том месте, где был сделан вызов. И это связано не с именем функции, а с самим вызовом функции, см., Например, https://en.wikipedia.org/wiki/Call_stack .
Так что даже если функция вызывает себя как
<?php
function foo($param) {
echo "foo($param) in", PHP_EOL;
if ( $param!==1 ) {
foo(1);
}
echo "foo($param) out", PHP_EOL;
}
foo(0);
это не приводит к тому, что один выход / возврат отменяет все вызовы функций «одной и той же» функции, а просто приводит к появлению одного «контекста» / фрейма в стеке вызовов. Поэтому вывод
foo(0) in
foo(1) in
foo(1) out
foo(0) out
Теперь сравните это с выводом «улучшенного» скрипта выше: я надеюсь, что это немного прояснит для вас.
Итак, я пытаюсь визуализировать, что здесь происходит, чтобы вы могли лучше понять, что происходит.
Вот что происходит (аннотация):
//Iteration 1
function(){
//Code before runs
if stmt (TRUE) //Iteration 2
function(); → function(){
←┐ //Code before runs
//Code after│
} │ if stmt (TRUE) //Iteration 10
│ function(); → ... → function(){
│ ←┐ //Code before runs
│ //Code after │
│ } │ if stmt (FALSE)
└──── ← function returns │
value and goes │ //Code after runs
back to next line │ }
└────── ← function returns value and goes back to next line
Таким образом, в 10-м вызове функции оператор if равен FALSE и больше не вызывает функции.
Теперь 10-й вызов функции выполняется до конца и уменьшает переменную.
Он возвращает возвращаемое значение (NULL) и возвращается к предыдущему вызову функции, который выполняет оставшуюся часть вызова функции, что также уменьшает переменную и так далее …