我正在使用PSR-3日志记录类,并且尝试与结合使用set_error_handler()
。我的问题是如何正确“捕获”日志记录对象?
快速示例:
我的ErrorHandler.php
:
set_error_handler(function ($errno, $errstr , $errfile , $errline , $errcontext) {
// This error code is not included in error_reporting
if (!(error_reporting() & $errno)) {
return;
}
$logger->log(/* How? */);
});
我的Logger.php
:
class Logger extends PsrLogAbstractLogger implements PsrLogLoggerInterface {
public function log($level, $message, array $context = array()) {
// Do stuff
}
}
请注意,记录器可能会启动也可能不会启动,其想法是使用户能够以某种方式轻松定义另一个记录器。
在我看来,我至少有两个选择,可以简单地使用称为$logger
或类似名称的全局变量,并使用它(即使Logger
在我的特定示例中不会在全局范围内初始化对象),也可以使用单例模式“仅此一次”,我将在Logger
类内部定义一个静态方法,以便可以使用诸如:
$logger = Logger::getInstance();
虽然我已经看到了很多非常恶劣的事情说一下Singleton模式,有的甚至称这是“反模式”。我正在为项目的其余部分使用依赖项注入(尽我所能)。
我是否缺少其他选择,还是有“正确”的方法来做到这一点?
通过在此处使用单例,您将隐藏Logger的依赖项。您在这里不需要全局访问点,并且由于您已经在尝试遵循DI,因此您可能不想使代码混乱并使之不可测试。
确实,有更清洁的方法可以实现这一目标。让我们经历一下。
您无需将闭包或函数名称传递给该set_error_handler
函数。这是文档说明的内容:
具有以下签名的回调。可以改为传递NULL,以将此处理程序重置为其默认状态。除了函数名称,还可以提供包含对象引用和方法名称的数组。
知道了这一点,您可以使用专用对象来处理错误。对象上的处理程序方法将像这样被调用set_error_handler
set_error_handler([$errorHandler, 'handle']);
$errorHandler
对象和handle
要调用的方法在哪里。
该ErrorHandler
班将负责为您的错误处理。通过使用类获得的好处是我们可以轻松地使用DI。
<?php
interface ErrorHandler {
public function handle( $errno, $errstr , $errfile = null , $errline = null , $errcontext = null );
}
class ConcreteErrorHandler implements ErrorHandler {
protected $logger;
public function __construct( Logger $logger = null )
{
$this->logger = $logger ?: new VoidLogger();
}
public function handle( $errno, $errstr , $errfile = null , $errline = null , $errcontext = null )
{
echo "Triggered Error Handler";
$this->logger->log('An error occured. Some Logging.');
}
}
该handle()
方法无需进一步讨论。它的签名符合set_error_handler()
功能的需求,我们通过定义合同来确保它的正确性。
这里有趣的部分是构造函数。我们在此处键入Logger
(接口),并允许传递null。
<?php
interface Logger {
public function log( $message );
}
class ConcreteLogger implements Logger {
public function log( $message )
{
echo "Logging: " . $message;
}
}
传递的Logger
实例将被分配给相应的属性。但是,如果未传递任何内容,VoidLogger
则会分配a的实例。它违反了DI的原理,但是在这种情况下完全可以,因为我们使用了特定的模式。
您的条件之一是:
请注意,记录器可能会启动也可能不会启动,其想法是使用户能够以某种方式轻松定义另一个记录器。
当您需要没有任何行为但想要遵守合同的对象时,可以使用“空对象模式”。
由于我们log()
在ErrorHandler的Logger上调用了方法,因此我们需要一个Logger
实例(不能在任何情况下调用方法)。但是没有人禁止我们创建不执行任何操作的Logger的具体实现。而这正是Null Object模式。
<?php
class VoidLogger implements Logger {
public function log( $message ){}
}
现在,如果您不想启用日志记录,请不要在实例化过程中将任何内容传递给错误处理程序,也不要VoidLogger
自己传递a 。
<?php
$errorHandler = new ConcreteErrorHandler(); // Or Pass a Concrete Logger instead
set_error_handler([$errorHandler, 'handle']);
echo $notDefined;
要使用您的PSR记录器,您只需要稍微调整一下记录器上的类型提示和方法调用即可。但是原理保持不变。
通过选择这种类型的实现,您可以获得以下好处:
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句