在软件开发中,我们经常需要为现有的对象或方法添加一些额外的功能,比如日志记录、性能监控、权限验证等。直接修改目标对象的源代码并不是一个好的做法,因为这样会增加代码的复杂性,并且违反"开闭原则"。
这时,拦截器模式就派上用场了。拦截器模式是一种非常有用的设计模式,它允许我们在不修改目标对象的情况下,对其进行功能增强或行为修改。
在本文中,我们将会实现一个简单的 PHP 拦截器,并演示如何使用它来记录方法调用日志。
拦截器的实现
首先,我们定义一个 InterceptorHandler
类,它负责管理目标对象和拦截器:
class InterceptorHandler
{
private $target;
private $interceptors = [];
public function __construct($target)
{
$this->target = $target;
}
public function addInterceptor($interceptor)
{
$this->interceptors[] = $interceptor;
}
public function __call($method, $arguments)
{
// 先执行拦截器
foreach ($this->interceptors as $interceptor) {
if ($interceptor->before($method, $arguments)) {
return $interceptor->around($method, $arguments, function () use ($method, $arguments) {
return call_user_func_array([$this->target, $method], $arguments);
});
}
}
// 如果拦截器没有阻止,则执行目标方法
return call_user_func_array([$this->target, $method], $arguments);
}
}
接下来,我们定义一个 Interceptor
接口,它定义了两个方法:
before($method, $arguments)
: 在目标方法执行之前执行,可以返回true
允许继续执行,或者false
阻止执行。around($method, $arguments, $proceed)
: 在目标方法执行的过程中执行,可以在目标方法执行前后添加自定义逻辑。
interface Interceptor
{
public function before($method, $arguments);
public function around($method, $arguments, $proceed);
}
最后,我们实现一个 LoggingInterceptor
类,它实现了 Interceptor
接口,在目标方法执行前后打印日志信息:
class LoggingInterceptor implements Interceptor
{
public function before($method, $arguments)
{
echo "Calling method: $method with arguments: " . implode(', ', $arguments) . "\n";
return true; // 允许继续执行
}
public function around($method, $arguments, $proceed)
{
$start = microtime(true);
$result = call_user_func_array($proceed, $arguments);
$end = microtime(true);
echo "Method $method took " . ($end - $start) . " seconds to execute.\n";
return $result;
}
}
使用拦截器
现在,我们可以创建一个 InterceptorHandler
实例,并添加 LoggingInterceptor
拦截器:
$target = new SomeClass();
$handler = new InterceptorHandler($target);
$handler->addInterceptor(new LoggingInterceptor());
$handler->someMethod(1, 2, 3);
$handler->anotherMethod('foo', 'bar');
当我们调用 someMethod
和 anotherMethod
时,LoggingInterceptor
会先执行,打印出方法调用信息和执行时间,然后再执行目标方法。
这个简单的拦截器实现展示了拦截器模式的基本思想。在实际应用中,我们可以根据需求添加更多的拦截器功能,比如权限验证、缓存、性能监控等。拦截器模式是一种非常灵活和可扩展的设计模式,可以帮助我们在不修改目标对象的情况下,为其添加新的功能。