2011-06-26 26 views
3

我已經決定使用閉包而不是create_function,因此只支持PHP> 5.3,這主要是由於增加了可調試性,也是因爲我認爲(他們對假設的看法是什麼? )在我的情況下,編譯create_function的開銷可能會抵銷任何額外的比較,並且必須在函數中進行。 (這對我的應用程序而言)並且需要進一步的測試,但是我對這個(非常)簡單的測試的輸出感興趣,它顯示了create_function方法的速度是當它只能刪除四個條件(連接)時關閉。很明顯,在我的測試用例中沒有額外的處理,這就是大部分速度會增加或者丟失的地方,但是如果你只有很少的額外處理,但是很多條件(可以被刪除)和回調被稱爲足夠多的時間,我開始認爲使用create_function可能會更好。PHP中的閉包或create_function

但是,由於create_functioneval之間有明顯的相似性,我很謹慎。

所以主要問題是用create_function創建的匿名函數與閉包的區別是什麼?

我在想的幾個具體問題是,當eval功能被禁用時,create_function甚至會工作嗎?而且,我確信我最近在某個地方讀到create_function函數即使聲明爲內部函數也會污染全局(或類)名稱空間,但閉包不會。我現在找不到這個提法,但是這兩個陳述中的一個或兩個是真的?


這是小測試,我跑:

<?php 

function foo($a=true, $b=true, $c=true, $d=true) 
{ 
    $inner1 = create_function(
     '', 
     '$r = \''.($a ? 'a' : ''). 
        ($b ? 'b' : ''). 
        ($c ? 'c' : ''). 
        ($d ? 'd' : '').'\'; 
     return $r;' 
    ); 


    $inner2 = function() use ($a, $b, $c, $d) 
    { 
     $r = ''; 
     if($a) { $r .= 'a'; } 
     if($b) { $r .= 'b'; } 
     if($c) { $r .= 'c'; } 
     if($d) { $r .= 'd'; }; 
     return $r; 
    }; 


    $time = microtime(true); 
    for ($x=0; $x<99999; ++$x) 
    { 
     $i1out = $inner1(); 
    } 
    echo '1:'.(microtime(true)-$time).'<br>'; 

    $time = microtime(true); 
    for ($x=0; $x<99999; ++$x) 
    { 
     $i2out = $inner2(); 
    } 
    echo '2:'.(microtime(true)-$time).'<br>'; 

    echo var_dump($i1out===$i2out).'<br>'; 
} 

foo(); 
+0

它應該很容易測試在哪個名稱空間'create_function' ..創建函數.. :) –

+0

我會去封閉也。就速度而言,也許你應該用真實世界的案例來測試它。我不知道爲什麼這個應該慢得多,但我會採取'打'。另外,APC在這種情況下是否有所作爲?閉包是否緩存在操作碼中?它也可能有所作爲。 – Arend

+0

將它們分開。這個問題已經很長了。 – phihag

回答

6

的結構function() {..}是一個匿名函數,這個功能經常與closures一起實施。 create_function和匿名函數都不會污染全局名稱空間。

由於匿名函數可以訪問周圍的變量(閉包部分),理論上它們可以稍微慢一些。另一方面,如果你使用字節碼緩存(如果你不是,你顯然不關心性能),我期望匿名函數的「編譯」開銷稍微慢一些。

但是,匿名函數和create_function之間的差異是造成性能問題的根源的可能性極小。因此,如果你非常幸運地擁有一個php> 5.3的目標平臺,我會選擇一個更具可讀性的匿名函數。

+1

那麼,這取決於你的意思是「污染全球命名空間」。 'create_function'確實創建了一個全局函數,但是它的名字不會和你用於函數的名字衝突。 – newacct

2

create_function創建一個全局函數,該函數在程序的其餘部分中保持不變。 create_function只是簡單地返回函數名(字符串),因此不知道你是否仍然有權訪問那個存儲在某處的名字。因此,即使您無法再訪問該名稱,也無法「收集垃圾」。

這意味着,一個很大的問題是,如果你創建了很多使用功能create_function,它會導致你的程序運行內存不足:

for ($i = 0; $i < 1000000; $i++) { 
    $f = create_function('', ''); 
    // do stuff 

    // don't use $f anywhere after this point 
} 

而用匿名函數,這不會發生(關閉將被垃圾收集)。