2009-01-06 83 views
66

在JavaScript中,嵌套函數非常有用:閉包,私有方法和你有什麼......什麼是PHP嵌套函數?

什麼是嵌套的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() 
+0

我本來可以發誓我讀到這個支持被丟棄在PHP6中,但我找不到它在任何地方。 – Greg 2009-01-06 10:18:06

+1

@greg我認爲PHP6的整個計劃是在空中嗎? – James 2011-02-10 22:40:42

+0

它們適合大型功能 - sorta遞歸組織 – JVE999 2014-05-27 02:08:19

回答

74

有沒有基本上,我一直這樣對待作爲解析器的副作用。

Eran Galperin誤認爲這些功能在某種程度上是私人的,他們只是簡單地未申報,直到outer()運行。它們也不是私人範圍的,它們確實會對全球範圍造成影響,儘管延遲了。作爲回調,外部回調仍然只能被調用一次。我仍然沒有看到如何將它應用於一個很可能不止一次調用別名的數組。

我可以挖掘的唯一'真實世界'例子是this,它只能運行一次,可以重寫清潔IMO。

我可以想到的唯一用途是用於模塊調用它設置在全局空間與

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

檢查相結合幾個嵌套方法[名稱] _include方法。

PHP的面向對象顯然是更好的選擇:)函數中定義

+0

是的,你是對的。我編輯了我的答案以反映它 – 2009-01-06 10:33:37

+9

是的,真的。這是非常糟糕的。 – 2009-09-29 17:06:23

+0

很好的示例鏈接。我應該開始實施,而不是繼承! – zanlok 2011-02-10 21:33:29

6

功能也看不出多大用處的,但是有條件地定義的功能,我可以。例如:

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」()的函數調用,所以你不要亂扔垃圾語言檢查在你的代碼。現在我還沒有這樣做,但我可以看到這樣做的理由。

69

如果你正在使用PHP 5.3,你可以用匿名函數獲得更多Javacript類似的行爲:

<?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 
0

嵌套函數是有用的記憶化(緩存功能結果提高性能)。

<?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); 
} 
?> 
2

所有我的PHP的是面向對象的,但我確實看到了使用了嵌套函數,特別是當你的函數是遞歸的,而不一定對象。也就是說,它不會在它所嵌套的函數之外被調用,而是遞歸的,並且隨後需要成爲一個函數。

在爲其他方法的快速使用制定新方法方面沒有多大意義。對我來說,這是笨拙的代碼和排序 - 而不是面向對象。如果你永遠不會在其他地方調用該功能,請將其嵌套。

9

[根據@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... ;) 
     } 
    } 
} 
1

在Web服務調用,我們發現這是一個非常低的開銷(內存和速度)動態地包括以嵌套的方式,在滿足1000個函數的函數庫上的各個函數。典型的調用堆棧可能在5-10個調用深度之間,只需要動態鏈接一個1到2kb的文件比包括兆字節更好。這只是通過創建一個包裝需要的小型util函數來完成的。包含的函數嵌套在調用堆棧上方的函數中。考慮一下,它與充滿100個函數的類不同,它們在每次web服務調用時都不需要,但也可以使用php的內置延遲加載特性。

1

以上所述,可以簡單地創建一個嵌套函數來替換函數中的一些本地化重複代碼(僅在父函數內部使用)。有些人可能會說只是創建私有方法(或者更小的代碼塊),但是當一個超特定的任務(這對父代是專有的)需要模塊化時,這會混淆水域,但不一定對其他類可用(或程序性程序中的全球空間)。好消息是,如果事實證明,你確實需要在其他地方的功能,修復是相當基本的(將定義移到更中心的位置)。一般來說,使用JavaScript作爲評估其他基於C的編程語言的標準是一個壞主意。與PHP,Python,Perl,C,C++和Java相比,JavaScript絕對是它自己的動物。當然,這裏有許多相似的地方,但是當注意時,細節(參考文獻JavaScript:權威指南,第6版,第1-12章)使得核心JavaScript獨特,美觀,不同,簡單,並且都在同一時間複雜。這是我的兩分錢。

要說清楚,我並不是說嵌套函數是私有的。只要嵌套可以幫助避免混亂時,需要模塊化的東西(只有父功能需要)。

0

如果要嵌套函數利用在父函數中聲明的變量,嵌套函數很有用。

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