Функция постепенно уменьшает статическую переменную, но не должна. Переполнение стека

Есть функция:

<?php

function test(){

static $count = 0;
$count++;
echo $count;

if ($count < 10) {
test();
}

$count--;
echo $count;
}

test();

?>

Этот код производит: 123456789109876543210

Когда $ count увеличивается до 10 — это понятно, он работает до тех пор, пока оператор не оценивается как false.
но почему оно постепенно уменьшается до 0?
В моей логике новичка $ count— в этом коде должен только уменьшиться до 9 один раз, и функция должна остановиться.
Не существует цикла или цикла, который может постепенно уменьшать его значение. Но мы видим, что это здесь и работает.
Почему так происходит?

1

Решение

Возможно, все становится немного яснее, когда вы меняете вывод, подчеркивая, как работает условный рекурсивный вызов:

<?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

Теперь сравните это с выводом «улучшенного» скрипта выше: я надеюсь, что это немного прояснит для вас.

2

Другие решения

Итак, я пытаюсь визуализировать, что здесь происходит, чтобы вы могли лучше понять, что происходит.

Вот что происходит (аннотация):

//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) и возвращается к предыдущему вызову функции, который выполняет оставшуюся часть вызова функции, что также уменьшает переменную и так далее …

2

По вопросам рекламы [email protected]