【问题标题】:Function decreases static variable step by step, but it should not. PHP函数逐步减少静态变量,但它不应该。 PHP
【发布时间】:2016-06-01 21:06:09
【问题描述】:

有一个功能:

<?php 

 function test(){

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

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

     $count--;  
     echo $count;
}

test();  

?>

此代码产生:123456789109876543210

当 $count 增加到 10 - 这是可以理解的,它会一直工作,直到 if 语句评估为 false。 但为什么它逐渐减少到0? 在我的新手逻辑中,此代码中的 $count-- 一次应该只减少到 9 并且函数应该停止。 没有循环或循环可以逐步降低其价值。但是我们看到,它在这里并且正在工作。 为什么会发生?

【问题讨论】:

  • 第一次递减后为什么要停止函数?您已经创建了一个递归函数 - 函数的前半部分有效地运行,然后如果 $count &lt; 10 为真,则创建该函数的一个新实例。当那最终为假时,函数的后半部分运行;然后函数的每个实例从它停止的地方继续,展开所有的函数调用。
  • 你见过递归函数吗?

标签: php static decrement


【解决方案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

现在将其与上面“改进”脚本的输出进行比较:我希望这对您有所帮助。

【讨论】:

  • 我真的很喜欢不同的例子,尤其是第二个用“in”和“out”来表示在OP的代码中调用函数之前和之后的代码。
  • @Rizier123 这是我所知道的在 SO 这样的地方将类似的东西可视化的唯一方法 ;-) 另一方面,这正是我希望开发人员 不 做的事情:使用 strinkydinky printf-debuggers 跟踪执行流程 ;-)
【解决方案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)并返回上一个函数调用,该函数调用执行其余的函数调用,这也减少了变量等等......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-23
    • 2021-05-19
    • 2016-12-23
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多