功能内的功能。


71

这段代码的结果为56。

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

    return($y+3);
}

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

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


26
听起来像是一个家庭作业问题,但这仍然是一个好问题哈哈。
hobbes3

Answers:


97

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

给定值为4,这表示(4+3) * (4*2) = 7 * 8 = 56

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

1)您不能在调用 y()之前调用x(),因为函数只有执行一次y()才实际定义x()

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

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

两者的解决方案是拆分代码,以便两个函数彼此独立地声明:

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

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

这也更具可读性。


57
另一个区别是,如果在函数x内有函数y,并且两次调用了函数x,则重新声明函数y会出错。(如果确实需要此功能,则需要在函数y的周围检查是否(function_exists('y')){...)
Eugene M,2009年

3
@Eugene M:我什至不知道。谢谢您指出!(在
重述

4
“这意味着您可以安全地嵌套函数定义,同时仍然可以在文件中的任何位置调用它们” –这是一种可怕的语言属性。
迈克尔

2
迈克尔,您可以使用匿名函数,将它们分配给变量并享受它,它将受到范围的限制。@Duroth,您还可以避免在使用匿名函数时重新声明错误。
Yevgeniy Afanasyev 2015年

因此,函数中函数的范围仍然是全局的(在定义文件的名称空间中)?
杰森

29
(4+3)*(4*2) == 56

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


谢谢,所以内部函数不会被调用。
Posto

1
调用X时,将定义内部函数-未调用。因此结果。那就是关于函数在函数中的毛茸茸的部分=)
mauris

@Lukas-我敢打赌,功能y()x()
启用

哦,好了,我应该再参考同一篇文档,它也解释了调用函数的语法。:)
卢卡斯·拉林斯基

16

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


2
同样,在x()中定义y()意味着x()只能被调用一次。第二次调用x()时,将出现“函数已定义”致命错误。
Anti Veeranna

8

这对于没有静态属性,引用等的递归非常有用:

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;
}

说明?看起来是递归的,但我看不到。是“ getReqursiveItems”在getItems()内部吗?
乔西亚2015年

1
@Josiah不知道我最初的想法在这里..但是我编辑了答案以显示可能的用例。
d.raev 2015年

3
这看起来根本不是递归的,而是返回原始$id
文档的

如果你先更换getItemsforeachgetItemms和第二getItemsgetReqursiveItems你会得到递归函数。
przemo_li

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


3

您的查询正在做7 * 8

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

发生的情况是当调用函数x时,它创建函数y,而不运行它。


1
只是想补充一点,这并不是很好的做法。您还将注意到,如果使用$ y = y($ y)* x($ y); 该代码将死,因为尚未创建x。这样的编码只会导致错误和混乱。
Michael Mior

是的,这是真的; 我个人在实践中只使用过一次,以说明不同样式的魔术引号。尽管那是在if语句而不是函数中()
Mike Valstar 09年

0

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

  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);

第二种方法是将child的函数范围限制为local而不是global,为此,您必须将函数定义为Anonymous函数并将其分配给local变量,然后该函数将仅在local范围内可用,并且将在每次调用main函数时重新声明并调用。

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);

请记住,子函数在主函数或全局函数堆栈之外将不可用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.