1

在我的许多网站上,我使用了一个名为“Logger”的自制 PHP 类(基本上,它用于将信息记录到日志文件中,并按日期:年/月......自动组织这些文件)。

我通过在我的引导文件中创建一个 Logger 实例来使用它(包含在任何地方):

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 类之外)来处理$mainLogger(接近单例设计模式的东西)的实例化和检索:

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 类的属性或方法都不会导致任何错误(错误日志记录是一个可选功能,如果 Logger 不存在,它不应该让应用程序崩溃)。

您如何看待这种方法,这是一个坏主意吗?这会给我带来一些麻烦吗?什么样的?

谢谢

PS:如果你想看 Logger 类,你可以在我的网站上下载

4

2 回答 2

4

您在此处描述的“问题”可以通过多种方式解决。最常见的3个是:

  1. 使用factory class. 工厂类是对象生成工厂。工厂本身是一个静态或单例类,在一个类中全局使用。

  2. 的使用Dependency Injection。使用这种技术,记录器类被注入到类的构造函数中。该类保留对记录器的引用以供以后使用。

  3. 使用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);
  }
}
于 2012-10-10T20:47:44.500 回答
1

我不相信你需要这个魔法课。

首先,这个魔法类没有实现Logger,所以类型提示(这是一件好事)不起作用。其次,由于您的魔术类没有实现或扩展Logger,任何 IDE 也不会在魔术类上显示自动完成功能。确实是坏事。

Logger如果之前没有加载,你只需要魔法类。这是非常基本的故障,应该很容易检测到。最简单的方法是将 包含Logger在现在具有魔术类的文件中。

另一方面,您如何保证您的功能getLogger()可用?如果Logger可能不可用,则功能可能相同,并且您的代码同样会失败。

代码改进:不要使用这个:

function getLogger(){
    global $mainLogger;

您不需要全局变量,您只需要一个变量来存储您的记录器以供以后检索。改用静态变量:

function getLogger(){
    static $mainLogger;

如果你在它那里,这个函数可以直接进入工厂类并被静态调用。然后该变量$mainLogger将成为该类的静态属性,可能在私有范围内。

于 2012-10-11T19:43:13.770 回答