PHP 嵌套函数是用来做什么的?

在 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()
60427 次浏览

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

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.

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

Nested functions are useful in Memoization (caching function results to improve performance).

<?php
function foo($arg1, $arg2) {
$cacheKey = "foo($arg1, $arg2)";
if (! getCachedValue($cacheKey)) {
function _foo($arg1, $arg2) {
// whatever
return $result;
}
$result = _foo($arg1, $arg2);
setCachedValue($cacheKey, $result);
}
return getCachedValue($cacheKey);
}
?>

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.

[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... ;)
}
}
}

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.

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

Nested functions are useful if you want the nested function to utilize a variable that was declared within the parent function.

<?php
ParentFunc();
function ParentFunc()
{
$var = 5;
function NestedFunc()
{
global $var;
$var = $var + 5;
return $var;
};
echo NestedFunc()."<br>";
echo NestedFunc()."<br>";
echo NestedFunc()."<br>";
}
?>

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

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

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...

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.