【问题标题】:Function inside a function.?函数中的函数。?
【发布时间】:2009-10-27 15:19:08
【问题描述】:

此代码产生的结果为 56。

function x ($y) {
    function y ($z) {
        return ($z*2);
    }

    return($y+3);
}

$y = 4;
$y = x($y)*y($y);
echo $y;

知道里面发生了什么吗?我很困惑。

【问题讨论】:

  • 听上去像是一道作业题,不过还是个好题哈哈。

标签: php function


【解决方案1】:

X 返回(值 +3),而 Y 返回(值*2)

给定值 4,这意味着 (4+3) * (4*2) = 7 * 8 = 56

虽然函数的范围不受限制(这意味着您可以安全地“嵌套”函数定义),但这个特定示例很容易出错:

1) 不能在调用x() 之前调用y(),因为函数y() 直到x() 执行一次后才会真正定义。

2) 两次调用x()会导致PHP重新声明函数y(),导致致命错误:

致命错误:无法重新声明 y()

解决方案是拆分代码,使两个函数声明为彼此独立:

function x ($y) 
{
  return($y+3);
}

function y ($z)
{
  return ($z*2);
}

这也更具可读性。

【讨论】:

  • 另一个区别是,如果你在函数 x 中有函数 y,并且你调用函数 x 两次,你会得到重新声明函数 y 的错误。 (如果你真的需要这个,你需要用检查 if (function_exists('y')) { ... ) 包围函数 y
  • @Eugene M:我什至都不知道.. 感谢您指出! (刚刚自己测试过,在修改了你的评论之后。)
  • “这意味着您可以安全地“嵌套”函数定义,同时仍然可以在文件中的任何位置调用它们”——这是一个可怕的语言属性。
  • Michael,你可以使用匿名函数,将它们分配给一个变量并享受,它的范围是有限的。 @Duroth,您还可以避免在使用匿名函数时重新声明错误。
  • 那么函数内函数的作用域还是全局的(在它定义的文件的命名空间内)?
【解决方案2】:
(4+3)*(4*2) == 56

请注意,PHP 并不真正支持“嵌套函数”,因为它仅在父函数的范围内定义。所有函数都是全局定义的。请参阅docs

【讨论】:

  • 谢谢,所以内部函数不会被调用。
  • 当 X 被调用时,内部函数被定义——不被调用。因此结果。这是关于函数中的函数的毛茸茸的部分 =)
  • @Lukas - 我敢打赌,提问者指的是功能 y()x() 中时的部分
  • 哦,好吧,我应该参考相同的文档,这也解释了 calling 函数的语法。 :)
【解决方案3】:

不确定该代码的作者想要实现什么。在另一个函数内部定义一个函数并不意味着内部函数只在外部函数内部可见。第一次调用 x() 后,y() 函数也将在全局范围内。

【讨论】:

  • 另外,在 x() 中定义 y() 意味着 x() 只能被调用一次。第二次调用 x() 时会出现“函数已定义”的致命错误。
【解决方案4】:

这对于没有静态属性、引用等的递归很有用:

function getRecursiveItems($id){
    $allItems = array();
    
    function getItems($parent_id){
       return DB::findAll()->where('`parent_id` = $parent_id');
    } 
   
    foreach(getItems($id) as $item){
         $allItems = array_merge($allItems, getItems($item->id) );
    }

    return $allItems;
}

【讨论】:

  • 解释一下?看起来是递归的,但我没有看到。 getItems() 中是否包含“getReqursiveItems”?
  • @Josiah 不确定我最初的想法是什么......但我编辑了答案以显示一个可能的用例。
  • 这看起来根本不是递归的,而是返回原始$id的所有grandchildren
  • 如果您将foreach 中的第一个getItems 替换为getItemms,将第二个getItems 替换为getReqursiveItems,您将获得递归函数。
【解决方案5】:

可以从另一个函数内部定义一个函数。 在外部函数执行之前,内部函数不存在。

echo function_exists("y") ? 'y is defined\n' : 'y is not defined \n';
$x=x(2);
echo function_exists("y") ? 'y is defined\n' : 'y is not defined \n';

输出

y 没有定义

y 已定义

简单的事情你不能在执行 x 之前调用函数 y

【讨论】:

    【解决方案6】:

    您的查询是 7 * 8

    x(4) = 4+3 = 7y(4) = 4*2 = 8

    当函数 x 被调用 创建 函数 y 时,它不会运行它。

    【讨论】:

    • 只是想补充一点,这不是很好的做法。您还会注意到,如果您使用 $y = y($y)*x($y);代码将死,因为 x 尚未创建。这样的编码只会导致错误和混乱。
    • 是的,这是真的;就我个人而言,我在实践中只使用过一次来应对不同风格的魔术引号。虽然那是在 if 语句而不是函数 ()
    【解决方案7】:

    函数内的函数或所谓的嵌套函数非常有用,如果您需要执行一些递归过程,例如循环真正的多层数组或文件树而不多个循环,或者有时我使用它来避免为需要在多个功能之间划分和隔离功能的小型作业创建类。但是在使用嵌套函数之前,您必须了解这一点

    1. 除非执行主函数,否则子函数将不可用
    2. 主函数执行后,子函数将可全局访问
    3. 如果您需要调用主函数两次,它将尝试重新定义子函数,这将引发致命错误

    这是否意味着您不能使用嵌套函数?不,您可以使用以下解决方法

    第一种方法是在函数存在的情况下使用条件块来阻止子函数重新声明到全局函数堆栈中,这样可以防止函数被多次声明到全局函数堆栈中。

    function myfunc($a,$b=5){
        if(!function_exists("child")){
            function child($x,$c){
                return $c+$x;   
            }
        }
        
        try{
            return child($a,$b);
        }catch(Exception $e){
            throw $e;
        }
        
    }
    
    //once you have invoke the main function you will be able to call the child function
    echo myfunc(10,20)+child(10,10);
    

    第二种方法是将子函数的作用域限制为局部而不是全局,为此,您必须将函数定义为匿名函数并将其分配给局部变量,然后该函数仅在本地范围内可用,并且每次调用主函数时都会重新声明和调用。

    function myfunc($a,$b=5){
        $child = function ($x,$c){
            return $c+$x;   
        };
        
        try{
            return $child($a,$b);
        }catch(Exception $e){
            throw $e;
        }
        
    }
    
    echo myfunc(10,20);
    

    记住子函数在主函数或全局函数堆栈之外是不可用的

    【讨论】:

      【解决方案8】:

      使用嵌套的第二次函数后,我们得到“重新声明”错误。但是..我们可以这样使用:

      function x( $some_value ){
      
      $nested_function = function($x){ return $x*2; };
      
      return $nested_function( $some_value );
      
      }
      

      【讨论】:

        猜你喜欢
        • 2017-08-22
        • 2012-11-26
        • 2022-06-26
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多