2013-01-19 46 views
0

有人能告訴我,最常見的原因,看看在PHP這樣的錯誤:無法銷燬活動lambda函數

無法銷燬活動拉姆達功能...

我猜某處有代碼試圖銷燬包含對自身的引用的閉包,編譯器對此感到惱火。

我們得到這些比我想要的更經常,我想知道我們使用什麼樣的模式,這是造成它的可能的罪魁禍首。

我會附上一段代碼,但錯誤通常指向文件而不是可能提供提示的文件中的一行。

回答

1

這樣會導致這樣的代碼一個致命的錯誤:

set_exception_handler(function ($e) { 
     echo "My exception handler"; 

     restore_exception_handler(); 

     throw new Exception("Throw this instead."); 
}); 
throw new Exception("An exception"); 

或者這樣:

function destroy_handler() { 
    restore_exception_handler(); 
} 

function update_handler() { 
    destroy_handler(); 
} 

set_exception_handler(function ($e) { 
     echo "My exception handler"; 

     update_handler(); 

     throw new Exception("Throw this instead."); 
}); 
throw new Exception("An exception"); 

當一個異常被拋出給set_exception_handler()回調執行並且一旦調用restore_exception_handler(),就會發生致命錯誤,因爲對該閉包的相同引用正在被de (或重新分配)在自己的範圍內(在Sameer K發佈的鏈接中的hanskrentel at yahoo dot de的示例中也是如此)。

從第二個例子可以看出,即使是嵌套的作用域,也會發生同樣的情況。這是因爲restore_exception_handler會銷燬最後一個設置的異常處理程序,而不是它的副本(就像在重新分配變量或取消設置時,仍然計算將給變量賦予初始值的表達式)。

如果您說代碼中的錯誤指向了另一個文件,我建議您檢查lambda中的所有調用,在函數和/或其他文件中的方法執行「跳轉」,並檢查是否重新分配或破壞對lambda本身的引用。

1

set_exception_handler將返回前一個異常處理程序:

返回先前定義的異常處理程序,或者在錯誤NULL的名稱。如果沒有定義以前的處理程序,則返回NULL。 php.net: set_exception_handler

<?php 

class MyException extends Exception {} 

set_exception_handler(function(Exception $e){ 
    echo "Old handler:".$e->getMessage(); 
}); 

$lastHandler = set_exception_handler(function(Exception $e) use (&$lastHandler) { 
    if ($e instanceof MyException) { 
     echo "New handler:".$e->getMessage(); 
     return; 
    } 

    if (is_callable($lastHandler)) { 
     return call_user_func_array($lastHandler, [$e]); 
    } 

    throw $e; 
}); 

觸發異常處理程序:

throw new MyException("Exception one", 1); 

輸出:New handler:Exception one

throw new Exception("Exception two", 1); 

輸出:Old handler:Exception two