【问题标题】:Simple recursive function is not working简单的递归函数不起作用
【发布时间】:2012-12-05 03:45:33
【问题描述】:

我正在尝试运行递归函数,但它无法正常工作。我在我的代码中没有看到任何错误,所以这可能是 PHP 无法实现的?

<?php

$herpNum = 0;

function herp() {
    if ($herpNum == 22) {
        echo "done";
    } else {
        $herpNum = $herpNum+1;
        echo $herpNum."<br/>";
        herp();
    }
}

herp();

?>

当我运行它时,结果只是一长串 1。

【问题讨论】:

  • PHP 没有像 JavaScript 一样工作的作用域链。
  • php.net/functions.user-defined - 在该页面上,请参阅 Example #4 Recursive functions 以获取类似但有效的变体。
  • 另外,请在提问前使用搜索。我很确定如何在 PHP 中编写递归函数的 QA 材料已经存在于网站上(在 PHP 手册本身旁边)。

标签: php function recursion scope


【解决方案1】:

因为 $herpNum 与函数不在同一个作用域,所以它在函数内部创建了一个新的 $herpNum,默认为 0,然后给它加 1。

您可以将其作为参数传入,也可以将其作为全局变量。

$herpNum = 0;

function herp($herpNum) {
    if ($herpNum == 22) {
        echo "done";
    } else {
        $herpNum = $herpNum+1;
        echo $herpNum."<br/>";
        herp($herpNum);
    }
}

herp($herpNum);

$herpNum = 0;

function herp() {
    global $herpNum;

    if ($herpNum == 22) {
        echo "done";
    } else {
        $herpNum = $herpNum+1;
        echo $herpNum."<br/>";
        herp();
    }
}

herp();

【讨论】:

  • 爆破,我忘了必须将变量定义为全局变量。我有一段时间没有制作 PHP 函数了:P
  • @CharlesJohnThompsonIII 但是,您确实应该避免使用全局变量。请改用带函数参数的版本。
  • 全局变量有什么问题?我得到的唯一其他答案没有任何意义。
  • 使用全局变量会污染全局命名空间,以后可能会造成冲突。另一个原因是 global 更难测试,因为如果不是不可能的话,对 global 使用 mock 或 dummy 通常会做更多的工作。
【解决方案2】:

这是因为您没有将参数$herpnum 传递给函数。

<?php

$herpNum = 0;

function herp($herpNum) {
    if ($herpNum == 22) {
        echo "done";
    } else {
        $herpNum = $herpNum+1;
        echo $herpNum."<br/>";
        herp($herpNum);
    }
}

herp($herpNum);

?>

应该可以的

【讨论】:

    【解决方案3】:

    问题是,每次调用herp() 时,$herpNum 都会重新定义为herp() 范围内的本地变量。这将导致递归循环,直到抛出“最大函数嵌套级别'100'达到......”错误。 (当您将 php ini 值 'display_errors' 设置为 'On' 时,您可以看到错误)

    把上面的代码改成:

    $herpNum = 0;
    
    function herp() {
        global $herpNum;
        if ($herpNum == 22) {
            echo "done";
        } else {
            $herpNum = $herpNum+1;
            echo $herpNum."<br/>";
            herp();
        }   
    }
    
    herp();
    

    请注意,如果$herpNum 仅由herp() 使用,最好将其声明为herp() 内的静态变量。

    function herp() {
        static $herpNum = 0;
        // ...
    

    static 关键字告诉 PHP 解释器在第一次调用函数时只初始化一次变量。这应该完全符合您的设计需求;)

    【讨论】:

    • 两个建议都是错误的,因为 PHP 中的递归作为参数传递。
    • 你正在打败函数递归的特性。每个函数调用都应该有自己的状态。静态和全局是单一状态,因此所有调用只有一个状态,而不是每次调用都有一个状态。
    • @hakre, @dualed global 'suggestion' 只是对提问者代码的更正,旨在回答他的问题。我不会在递归函数中使用全局变量,是的。但这不是问题所在。关于静态方法,可能有人认为不同,但是 php 手册至少 mentioned 它。
    • @hakre 然而,这个问题的最佳解决方案——将数字从 0 到 22 打印到屏幕上——将是迭代,不是吗? ;)
    【解决方案4】:

    试试:

    $herpNum = 0;
    
    function herp() {
        global $herpNum;
        if ($herpNum == 22) {
            echo "done";
        } else {
            $herpNum = $herpNum+1;
            echo $herpNum."<br/>";
            herp();
        }
    }
    herp();
    

    但出于安全原因,不建议这样做。

    这是一个例子:

    ...
    if( $admin == true ) {
      echo 'yeah! You are the admin!';
    }
    ...
    

    如果$admin 被声明为全局且未正确验证,则只需键入http://mysite.com/?admin=true 即可通过测试。

    顺便说一句...对于递归,最好将“环境”(一个或多个参数)作为参数注入:

    herp($herpNum=0); // if nothing is given, $herpNum is set to 0
    

    【讨论】:

    • 您能否详细说明这些安全原因?我认为全局变量没有问题。
    • 但这仅适用于通过 $admin = $_GET['admin']; 设置 $admin 的情况,不是吗?
    • 如果你使用$admin=$_GET['admin'],那么稍后在你的函数调用中你会得到这个:function doSomething($admin=false) {...}doSomething() 调用而没有unset($admin)$admin 将被视为“真” .顺便说一句,如果提供了$_GET['admin'],我相信您可以找到一些设置$admin 的配置。
    • 他说的是register_globals,默认是关闭的。如果你打开它,那么如果 $_GET['admin'] 可用,那么 $admin 也可用,它们将是 ===。
    • 是的@Supericy。但是global $admin=$_GET['admin'] 不需要 register_global 是不安全的。
    猜你喜欢
    • 2018-07-14
    • 2018-04-02
    • 2014-04-03
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    • 2021-11-28
    相关资源
    最近更新 更多