PHP 嵌套函数有什么用?

发布于 2024-07-11 11:30:38 字数 498 浏览 5 评论 0原文

在 JavaScript 中,嵌套函数非常有用:闭包、私有方法等等。

嵌套 PHP 函数的用途是什么? 有人使用它们吗?用途是什么?

这是我做的一个小调查

<?php
function outer( $msg ) {
    function inner( $msg ) {
        echo 'inner: '.$msg.' ';
    }
    echo 'outer: '.$msg.' ';
    inner( $msg );
}

inner( 'test1' );  // Fatal error:  Call to undefined function inner()
outer( 'test2' );  // outer: test2 inner: test2
inner( 'test3' );  // inner: test3
outer( 'test4' );  // Fatal error:  Cannot redeclare inner()

In JavaScript nested functions are very useful: closures, private methods and what have you..

What are nested PHP functions for? Does anyone use them and what for?

Here's a small investigation I did

<?php
function outer( $msg ) {
    function inner( $msg ) {
        echo 'inner: '.$msg.' ';
    }
    echo 'outer: '.$msg.' ';
    inner( $msg );
}

inner( 'test1' );  // Fatal error:  Call to undefined function inner()
outer( 'test2' );  // outer: test2 inner: test2
inner( 'test3' );  // inner: test3
outer( 'test4' );  // Fatal error:  Cannot redeclare inner()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

东京女 2024-07-18 11:30:38

如果您使用 PHP 5.3,您可以通过匿名函数获得更多类似 JavaScript 的行为:

<?php
function outer() {
    $inner=function() {
        echo "test\n";
    };

    $inner();
}

outer();
outer();

inner(); //PHP Fatal error:  Call to undefined function inner()
$inner(); //PHP Fatal error:  Function name must be a string
?>

输出:

test
test

If you are using PHP 5.3 you can get more JavaScript-like behaviour with an anonymous function:

<?php
function outer() {
    $inner=function() {
        echo "test\n";
    };

    $inner();
}

outer();
outer();

inner(); //PHP Fatal error:  Call to undefined function inner()
$inner(); //PHP Fatal error:  Function name must be a string
?>

Output:

test
test
非要怀念 2024-07-18 11:30:38

基本上是没有的。 我一直将此视为解析器的副作用。

Eran Galperin 错误地认为这些函数在某种程度上是私有的。 在 outer() 运行之前,它们只是未声明。 它们也不属于私人范围; 它们确实污染了全球范围,尽管是延迟的。 作为回调,外部回调仍然只能调用一次。 我仍然不明白将它应用于数组有什么帮助,这很可能多次调用别名。

我可以挖掘的唯一“现实世界”示例是 this,只能运行一次,并且可以重写得更干净,IMO。

我能想到的唯一用途是模块调用 [name]_include 方法,该方法在全局空间中设置多个嵌套方法,并结合

if (!function_exists ('somefunc')) {
  function somefunc() { }
}

检查。

PHP 的 OOP 显然是更好的选择:)

There is none basically. I've always treated this as a side effect of the parser.

Eran Galperin is mistaken in thinking that these functions are somehow private. They are simply undeclared until outer() is run. They are also not privately scoped; they do pollute the global scope, albeit delayed. And as a callback, the outer callback could still only be called once. I still don't see how it's helpful to apply it on an array, which very likely calls the alias more than once.

The only 'real world' example I could dig up is this, which can only run once, and could be rewritten cleaner, IMO.

The only use I can think of, is for modules to call a [name]_include method, which sets several nested methods in the global space, combined with

if (!function_exists ('somefunc')) {
  function somefunc() { }
}

checks.

PHP's OOP would obviously be a better choice :)

优雅的叶子 2024-07-18 11:30:38

[根据@PierredeLESPINAY 的评论重写。]

这根本不只是副作用,而且实际上是动态修改程序逻辑的一个非常有用的功能。 它来自过程化 PHP 时代,但如果您想以最直接的方式为某些独立函数提供替代实现,那么它也可以在 OO 架构中派上用场。 (虽然大多数情况下 OO 是更好的选择,但它是一个选项,而不是强制要求,并且一些简单的任务不需要额外的麻烦。)

例如,如果您从框架动态/有条件地加载插件,并且想要为了让插件作者的生活变得超级轻松,您可以为插件未覆盖的一些关键功能提供默认实现:

<?php // Some framework module

function provide_defaults()
{
    // Make sure a critical function exists:
    if (!function_exists("tedious_plugin_callback"))
    {
        function tedious_plugin_callback()
        {
        // Complex code no plugin author ever bothers to customize... ;)
        }
    }
}

[Rewritten according to the comment by @PierredeLESPINAY.]

It's not just a side-effect at all, but actually a very useful feature for dynamically modifying the logic of your program. It's from the procedural PHP days, but can come in handy with OO architectures too, if you want to provide alternative implementations for certain standalone functions in the most straightforward way possible. (While OO is the better choice most of the time, it's an option, not a mandate, and some simple tasks don't need the extra cruft.)

For example, if you dynamically/conditionally load plugins from your framework, and want to make the life of the plugin authors super easy, you can provide default implementations for some critical functions the plugin didn't override:

<?php // Some framework module

function provide_defaults()
{
    // Make sure a critical function exists:
    if (!function_exists("tedious_plugin_callback"))
    {
        function tedious_plugin_callback()
        {
        // Complex code no plugin author ever bothers to customize... ;)
        }
    }
}

函数内定义的函数我看不出有什么用处,但条件定义的函数我可以。 例如:

if ($language == 'en') {
  function cmp($a, $b) { /* sort by English word order */ }
} else if ($language == 'de') {
  function cmp($a, $b) { /* sort by German word order; yes it's different */ }
} // etc

然后您的所有代码需要做的就是在 usort() 调用之类的事情中使用“cmp”函数,这样您就不会在代码中乱扔语言检查。 现在我还没有这样做,但我可以看到这样做的论据。

Functions defined within functions I can't see much use for but conditionally defined functions I can. For example:

if ($language == 'en') {
  function cmp($a, $b) { /* sort by English word order */ }
} else if ($language == 'de') {
  function cmp($a, $b) { /* sort by German word order; yes it's different */ }
} // etc

And then all your code needs to do is use the 'cmp' function in things like usort() calls so you don't litter language checks all over your code. Now I haven't done this but I can see arguments for doing it.

巡山小妖精 2024-07-18 11:30:38

综上所述,人们可以简单地创建一个嵌套函数来替换函数中的一些本地化的重复代码(仅在父函数内部使用)。 匿名函数就是一个完美的例子。

有些人可能会说只在类中创建私有方法(或更小的代码块),但是当超特定任务(父级独有)需要模块化但不一定可供其他任务使用时,这就会把水搅浑。一类。 好消息是,如果事实证明您确实在其他地方需要该函数,则修复方法相当简单(将定义移动到更中心的位置)。

一般来说,使用 JavaScript 作为评估其他基于 C 的编程语言的标准是一个坏主意。 与 PHP、Python、Perl、C、C++ 和 Java 相比,JavaScript 绝对是它自己的动物。 当然,它们有很多普遍的相似之处,但是,如果关注一些细节,就会使核心 JavaScript 变得独一无二,美丽、不同、简单、复杂。 这是我的两分钱。

需要澄清的是,我并不是说嵌套函数是私有的。 只是当一些琐碎的事情需要模块化时(并且只有父函数需要),嵌套可以帮助避免混乱。

All the above being said, one might simply create a nested function to replace some localized, repetitive code within a function (that will only be used inside the parent function). An anonymous function is a perfect example of this.

Some might say just create private methods (or smaller code blocks) in a class, but that is muddying the waters when an ultra-specific task (which is exclusive to the parent) needs to be modularized, but not necessarily available to the rest of a class. The good news is if it turns out that you do need that function somewhere else, the fix is rather elementary (move the definition to a more central location).

Generally speaking, using JavaScript as the standard by which to evaluate other C based programming languages is a bad idea. JavaScript is definitely its own animal when compared to PHP, Python, Perl, C, C++, and Java. Of course, there are lots of general similarities, but the nitty, gritty details (reference JavaScript: The Definitive Guide, 6th Edition, Chapters 1-12), when paid attention to, make core JavaScript unique, beautiful, different, simple, and complex all at the same time. That's my two cents.

Just to be clear, I'm not saying nested functions are private. Just that nesting can help avoid clutter when something trivial needs to be modularized (and is only needed by the parent function).

疯到世界奔溃 2024-07-18 11:30:38

我所有的 php 都是面向对象的,但我确实看到了嵌套函数的用途,特别是当您的函数是递归的并且不一定是对象时。 也就是说,它不会在嵌套的函数之外被调用,而是递归的,因此需要是一个函数。

为明确使用单个其他方法而创建新方法没有什么意义。 对我来说,这是笨拙的代码,而且不是面向对象的重点。 如果您永远不会在其他地方调用该函数,请将其嵌套。

All of my php is OO, but I do see a use for nested functions, particularly when your function is recursive and not necessarily an object. That is to say, it does not get called outside of the function it is nested in, but is recursive and subsequently needs to be a function.

There's little point in making a new method for the express use of a single other method. To me that's clumsy code and sort-of not the point of OO. If you're never going to call that function anywhere else, nest it.

四叶草在未来唯美盛开 2024-07-18 11:30:38

在 Web 服务调用中,我们发现它的开销(内存和速度)要低得多,动态地以嵌套方式包含包含数千个函数的库中的各个函数。 典型的调用堆栈可能有 5-10 个调用深度,仅需要动态链接十几个 1-2kb 文件,这比包含兆字节要好。 这只是通过创建一个小的 util 函数包装 require 来完成的。 包含的函数将嵌套在调用堆栈上方的函数中。 将其与包含数百个函数的类进行对比,这些函数并非每次 Web 服务调用都需要,但也可以使用 php 内置的延迟加载功能。

In webservice calling we found it a much lower overhead (memory and speed) dynamically including in a nested fashion, individual functions over libraries full of 1000s of functions. The typical call stack might be between 5-10 calls deep only requiring linking a dozen 1-2kb files dynamically was better than including megabytes. This was done just by creating a small util function wrapping requires. The included functions become nested within the functions above the call stack. Consider it in contrast to classes full of 100s of functions that weren't required upon every webservice call but could also have used the inbuilt lazy loading features of php.

巡山小妖精 2024-07-18 11:30:38

如果您使用的是 php 7,请查看以下内容:
这个实现将使您对嵌套函数有一个清晰的了解。
假设我们有三个函数(too()、boo() 和zoo())嵌套在函数foo() 中。
boo() 和zoo() 具有相同名称的嵌套函数xoo()。 现在在这段代码中我已经清楚地注释掉了嵌套函数的规则。

   function foo(){
        echo 'foo() is called'.'<br>';
        function too(){
            echo 'foo()->too() is called'.'<br>';
        }
        function boo(){
            echo 'foo()->boo() is called'.'<br>';
            function xoo(){
                echo 'foo()->boo()->xoo() is called'.'<br>';
            }
            function moo(){
                echo 'foo()->boo()->moo() is called'.'<br>';
            }
        }
        function zoo(){
            echo 'foo()->zoo() is called'.'<br>';
            function xoo(){     //same name as used in boo()->xoo();
                echo 'zoo()->xoo() is called'.'<br>';
            }
        #we can use same name for nested function more than once 
        #but we can not call more than one of the parent function
        }
    }

/****************************************************************
 * TO CALL A INNER FUNCTION YOU MUST CALL OUTER FUNCTIONS FIRST *
 ****************************************************************/
    #xoo();//error: as we have to declare foo() first as xoo() is nested in foo()

    function test1(){
        echo '<b>test1:</b><br>';
        foo(); //call foo()
        too();
        boo();
        too(); // we can can a function twice
        moo(); // moo() can be called as we have already called boo() and foo()
        xoo(); // xoo() can be called as we have already called boo() and foo()
        #zoo(); re-declaration error
        //we cannont call zoo() because we have already called boo() and both of them have same named nested function xoo()
    }

    function test2(){
        echo '<b>test2:</b><br>';
        foo(); //call foo()
        too();
        #moo(); 
        //we can not call moo() as the parent function boo() is not yet called
        zoo(); 
        xoo();
        #boo(); re-declaration error
        //we cannont call boo() because we have already called zoo() and both of them have same named nested function xoo()

    }

现在,如果我们调用 test1() ,输出将是这样的:

test1:
foo() is called
foo()->too() is called
foo()->boo() is called
foo()->too() is called
foo()->boo()->moo() is called
foo()->boo()->xoo() is called

如果我们调用 test2() ,输出将是这样:

test2:
foo() is called
foo()->too() is called
foo()->zoo() is called
zoo()->xoo() is called

但我们不能同时调用 text1() 和 test2() 以避免重新声明错误

if you are in php 7 then see this:
This implementation will give you a clear idea about nested function.
Suppose we have three functions(too(), boo() and zoo()) nested in function foo().
boo() and zoo() have same named nested function xoo(). Now in this code I have commented out the rules of nested functions clearly.

   function foo(){
        echo 'foo() is called'.'<br>';
        function too(){
            echo 'foo()->too() is called'.'<br>';
        }
        function boo(){
            echo 'foo()->boo() is called'.'<br>';
            function xoo(){
                echo 'foo()->boo()->xoo() is called'.'<br>';
            }
            function moo(){
                echo 'foo()->boo()->moo() is called'.'<br>';
            }
        }
        function zoo(){
            echo 'foo()->zoo() is called'.'<br>';
            function xoo(){     //same name as used in boo()->xoo();
                echo 'zoo()->xoo() is called'.'<br>';
            }
        #we can use same name for nested function more than once 
        #but we can not call more than one of the parent function
        }
    }

/****************************************************************
 * TO CALL A INNER FUNCTION YOU MUST CALL OUTER FUNCTIONS FIRST *
 ****************************************************************/
    #xoo();//error: as we have to declare foo() first as xoo() is nested in foo()

    function test1(){
        echo '<b>test1:</b><br>';
        foo(); //call foo()
        too();
        boo();
        too(); // we can can a function twice
        moo(); // moo() can be called as we have already called boo() and foo()
        xoo(); // xoo() can be called as we have already called boo() and foo()
        #zoo(); re-declaration error
        //we cannont call zoo() because we have already called boo() and both of them have same named nested function xoo()
    }

    function test2(){
        echo '<b>test2:</b><br>';
        foo(); //call foo()
        too();
        #moo(); 
        //we can not call moo() as the parent function boo() is not yet called
        zoo(); 
        xoo();
        #boo(); re-declaration error
        //we cannont call boo() because we have already called zoo() and both of them have same named nested function xoo()

    }

Now if we call test1() the output will be this:

test1:
foo() is called
foo()->too() is called
foo()->boo() is called
foo()->too() is called
foo()->boo()->moo() is called
foo()->boo()->xoo() is called

if we call test2() the output will be this:

test2:
foo() is called
foo()->too() is called
foo()->zoo() is called
zoo()->xoo() is called

But we cannot call both text1() and test2() at same time to avoid re-declaration error

独﹏钓一江月 2024-07-18 11:30:38

对于那些认为嵌套函数没有实际用途的人。 是的,它们有用途,这就是一个例子。

想象一下,我有一个名为 my_file.php 的文件,用于获取 ajax 结果。 但是,如果有时您不想通过 ajax 获取结果,但又想在同一个页面中包含两次而不发生冲突,该怎么办?

假设 ajax 文件 my_file.php :

<?php
// my_file.php used for ajax

$ajax_json_in = 10; 

function calculations($a, $b)
{   $result = $a + $b;
    return $result;
}

$new_result = $ajax_json_in * calculations(1, 2);

$ajax_json_out =  $new_result; 
   
?>

下面的示例包含上述文件两次,没有冲突。 您可能不想使用 ajax 调用它,因为在某些情况下您需要将其直接包含在 HTML 中。

<?php
// include the above file my_file.php instead of ajaxing it

function result1 
{
    $ajax_json_in = 20; 
    include("my_file.php");
    return $ajax_json_out; 
}


function result2 
{
    $ajax_json_in = 20; 
    include("my_file.php");
    return $ajax_json_out;
}

?>

包含该文件会使文件的函数嵌套。 该文件用于 ajax 调用和内联包含!

所以在现实生活中嵌套函数是有用的。

祝你今天过得愉快。

For those that suggest that there is no practical use of nested functions. Yes they have use and this is an example.

Imagine that I have a file called my_file.php which is used to get an ajax result out of. But what if there are times that you don't want to get the result through ajax but you want to include it twice in the same page without conflicts?

Lets say ajax file my_file.php :

<?php
// my_file.php used for ajax

$ajax_json_in = 10; 

function calculations($a, $b)
{   $result = $a + $b;
    return $result;
}

$new_result = $ajax_json_in * calculations(1, 2);

$ajax_json_out =  $new_result; 
   
?>

Below example includes the above file twice without conflict. You may not want to ajax call it, because there are cases that you need to include it straight in the HTML.

<?php
// include the above file my_file.php instead of ajaxing it

function result1 
{
    $ajax_json_in = 20; 
    include("my_file.php");
    return $ajax_json_out; 
}


function result2 
{
    $ajax_json_in = 20; 
    include("my_file.php");
    return $ajax_json_out;
}

?>

Including the file makes the file's functions nested. The file is used both for ajax calls and inline includes !!!

So there is use in real life of nested functions.

Have a nice day.

爱的那么颓废 2024-07-18 11:30:38

我知道这是一篇旧文章,但 fwiw 当我只需要本地功能时,我使用嵌套函数为递归调用提供一种整洁的方法 - 例如用于构建分层对象等(显然你需要小心,父函数只是调用一次):

function main() {
    // Some code

    function addChildren ($parentVar) {
        // Do something
        if ($needsGrandChildren) addChildren ($childVar);
    }
    addChildren ($mainVar); // This call must be below nested func

    // Some more code
}

与 JS 相比,php 中需要注意的一点是,对嵌套函数的调用需要在函数声明之后(即函数声明下方)进行(与 JS 相比,函数调用可以在父函数中的任何位置)

I know this is an old post but fwiw I use nested functions to give a neat and tidy approach to a recursive call when I only need the functionality locally - e.g. for building hierarchical objects etc (obviously you need to be careful the parent function is only called once):

function main() {
    // Some code

    function addChildren ($parentVar) {
        // Do something
        if ($needsGrandChildren) addChildren ($childVar);
    }
    addChildren ($mainVar); // This call must be below nested func

    // Some more code
}

A point of note in php compared with JS for instance is that the call to the nested function needs to be made after, i.e. below, the function declaration (compared with JS where the function call can be anywhere within the parent function

£冰雨忧蓝° 2024-07-18 11:30:38

我仅在以下情况下才真正使用此特性:在主要的、更明确的函数中执行小型递归函数很有用,但又不想将其移动到不同的文件,因为它是主要进程的行为的基础。 我意识到还有其他“最佳实践”方法可以做到这一点,但我想确保我的开发人员每次查看我的解析器时都能看到该功能,这可能是他们应该修改的内容......

I have only really used this characteristic when it was useful to execute a small recursive function inside a primary, more categorical function, but didn't want to move it to a different file because it was fundamental to the behavior of a primary process. I realize there are other "best practice" ways of doing this, but I want to make sure my devs see that function every time they look at my parser, it's likely what they should modify anyway...

佞臣 2024-07-18 11:30:38

基于 这个答案,您可以使用 use 子句使内部函数递归:

<?php
function outer() {
    $inner = function ($i = 0) use (&$inner) {
        if ($i < 10) {
            echo "test $i\n";
            $inner($i + 1);
        }
    };

    $inner();
}

outer();
outer();

?>

如果您有其他变量要带入闭包中,也添加它们:

<?php
function outer($count) {
    $inner = function ($i = 0) use (&$inner, $count) {
        if ($i < $count) {
            echo "test $i\n";
            $inner($i + 1);
        }
    };

    $inner();
}

outer(3);
outer(5);

?>

与父答案一样,此模式确保内部函数不会泄漏到全局范围。

Building on this answer, you can make the inner function recursive with a use clause:

<?php
function outer() {
    $inner = function ($i = 0) use (&$inner) {
        if ($i < 10) {
            echo "test $i\n";
            $inner($i + 1);
        }
    };

    $inner();
}

outer();
outer();

?>

If you have other variables to bring into the closure, add them as well:

<?php
function outer($count) {
    $inner = function ($i = 0) use (&$inner, $count) {
        if ($i < $count) {
            echo "test $i\n";
            $inner($i + 1);
        }
    };

    $inner();
}

outer(3);
outer(5);

?>

As with the parent answer, this pattern ensures the inner function doesn't leak out to the global scope.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文