2012-10-10 20 views
1

在我的許多網站上,我使用了一個名爲「Logger」的自制PHP類(基本上,它旨在將信息記錄到日誌文件中,並按日期:年/月...自動組織這些文件)。使用「魔法類」來避免PHP致命錯誤,好主意?

我使用它在我的引導文件創建記錄器的實例(包括無處不在):

require 'lib/Logger.class.php'; 
$mainLogger = new Logger('./my_log_folder'); 

這迫使我設置$mainLogger全球在每一個需要登錄的東西的功能,同時檢查如果記錄器調用之前實例化的任何方法:

function foo($bar){ 
    global $mainLogger; 
    if(!is_null($mainLogger)){ 
     // If the logger is instanciated, I can log my message 
     $mainLogger->log('error', 'mysql-errors', "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH); 
    } 
} 

爲了使這個工具更易於使用和寫更少的代碼,我在想創建一個函數(Logger類外),處理的instanciation和檢索$mainLogger(一些接近singleton設計模式):

function getLogger(){ 
    global $mainLogger; 
    if(!isset($mainLogger)){ 
     if(class_exists('Logger')){ 
      // Instanciation of the main logger 
      $mainLogger = new Logger('./my_log_folder'); 
     } else { 
      // The Logger class doesn't exists, so we'll return a magical object to "mimic" the logger attributes & methods, thus avoiding fatal errors 
      return new MagicalClass(); 
     } 
    } 
    return $mainLogger; 
} 

class MagicalClass { 
    public function __get($name){ 
     return; 
    } 
    public function __call($name, $args){ 
     return $this; // Allow to chain calls to this class, like jQuery : getLogger->foo()->bar()... 
    } 
} 

的MagicalClass是爲了避免致命錯誤(致命錯誤:調用未定義的方法...),可以通過調用這個例如提高(不Logger.class .PHP包括):

getLogger->log('error', 'mysql-errors', "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH); 

由於_ 呼叫 _GET,任何企圖利用Logger類的屬性或方法不會引起任何錯誤(錯誤日誌是一個可選功能,它建議立即進行刪除只要記錄器不存在,不要使應用程序崩潰)。

您對這種方法有什麼看法,這是一個壞主意嗎? 這可以引起我一些麻煩,什麼樣的?

感謝

PS:如果你想看到的Logger類,你可以下載它在我的網站here

+0

致命錯誤不應發生在生產代碼中。致命錯誤通常是非常嚴重的運行時錯誤,或者更糟的是,語法錯誤(語法錯誤是編譯時,它們不能以任何編程的方式記錄,並且總是致命的)。 –

+0

JvdBerg的回答在我看來是正確的。雖然使用包含日誌記錄功能的公共基類可能會快速修復?您可以在基本類中使用延遲加載方法,在第一次調用時實例化記錄器。在這種情況下,我不會使用魔法,魔法=神祕。在代碼庫中,我認爲神祕是不好的。在這種情況下,您需要處理日誌記錄可能不存在的事實,因此請將所有可能調用它的對象呈現給它。 – Gavin

+2

這不是處理錯誤的好方法,並且有許多無法避免的致命錯誤(例如語法)。在整個代碼庫中使用類似這樣的類將您的代碼緊密地結合到日誌實現中。 [請參閱我的答案](http://stackoverflow.com/questions/10331084/error-logging-in-a-smooth-way/10538836#10538836)瞭解錯誤處理選項的詳細說明。 – Paul

回答

4

您在這裏描述的'問題'可以通過多種方式解決。最常見的3種是:

  1. 使用factory class。工廠類是生成工廠的對象。工廠本身是一個靜態或單一類,全局使用在一個類中。使用Dependency Injection。使用這種技術,記錄器類被注入到類的構造函數中。該類保留對日誌記錄器的引用以供日後使用。

  2. 使用Inversion of Control(IoC)容器。這是1和2的組合。容器保存的是一個列表創建的對象,並且當需要一個新對象時,它會被創建並且相關對象會自動注入到構造器中。

例子:

工廠類

class Foo 
{ 
    public function Bar() 
    { 
    $logger = ClassFactory::CreateLogger(); 

    $logger->log('error', 'mysql-errors', 
     "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH); 
    } 
} 

依賴注入

class Foo 
{ 
    private $logger; 

    public function __construct($logger) 
    { 
    $this->logger = $logger; 
    } 

    public function Bar() 
    { 
    $this->logger->log('error', 'mysql-errors', 
     "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH); 
    } 
} 
1

我不認爲你需要這個魔法類。

首先,這個魔法類沒有實現Logger,所以typehinting(這是一件好事)將不起作用。其次,由於你的魔法類沒有實現或擴展Logger,任何IDE也不會在魔術類上顯示自動完成。確實是壞事。

如果之前未加載Logger,則只需要魔法類。這是非常基本的失敗,應該很容易檢測到。最簡單的方法是將Logger包含在現在具有魔術類的文件中。

另一方面,你如何保證你的功能getLogger()可用?如果Logger可能不可用,則該函數可能會相同,並且您的代碼也會同樣失敗。

代碼改進:請不要使用此:

function getLogger(){ 
    global $mainLogger; 

你並不需要一個全局變量,你只需要存儲你對以後的檢索記錄的變量。改用一個靜態變量:

function getLogger(){ 
    static $mainLogger; 

如果你在這裏,這個函數可以直接進入一個工廠類並被靜態調用。變量$mainLogger將成爲該類的靜態屬性,可能在私人範圍內。

+0

getLogger將始終可用,因爲我會將其寫入我的應用程序的核心庫文件中。 我沒有想過使用靜態,謝謝你的提示。 – Vince

+0

這就是你的記錄器應該被要求的地方。問題解決了,不需要魔法。 – Sven