我想在每次使用方法之前和之后添加一些逻辑(在私有,保护或公共时无关紧要)。
例如:
class Service
{
function test1() {
Log:start(__METHOD__);
someLogicInThere(); ....
Log:end(__METHOD__);
}
function test2() {
Log:start(__METHOD__);
someLogicInThere(); ....
Log:end(__METHOD__);
}
...
}
我的想法是终于得到这样的东西:
/**
* @LogDecorate
*/
class Service
{
function test1() {
someLogicInThere();
}
function test2() {
someLogicInThere();
}
...
}
使用注释并不重要。有办法吗?
答案 0 :(得分:1)
正如您的问题标题已经建议的那样,您可以使用Decorator Pattern。我不太确定这里是否需要一个全栈装饰器模式。如果它是一个非常简单的用例,那么这样就足够了。
您可以做的是扩展类并将所有调用“路由”到扩展类。然后在之前和之后添加一些逻辑,并在其间调用父方法。像这样:
class Service {
function method1() {
doSomeFunkyStuff();
}
function method2() {
doSomeOtherFunkyStuff();
}
}
class DecoratedService extends Service {
function method1() {
Log::start(__METHOD__);
parent::method1();
Log::end(__METHOD__);
}
function method2() {
Log::start(__METHOD__);
parent::method2();
Log::end(__METHOD__);
}
}
$service = new DecoratedService();
$service->method1();
$service->method2();
现在,您可以选择使用原始Service
或使用DecoratedService
。功能性是相同的,如果DecoratedService
发生变化,Service
将不会改变,假设方法名称不会改变(这实际上是一件坏事)。
但是也要查看wiki页面(或任何其他资源)以完全理解Decorator Pattern的意图。这(上图)可能不是您问题的理想解决方案。
编辑根据要求更自动,先生。
由于无法更改方法的可见性,因此使用魔术__call()
不起作用(因为也可以从子级访问公共或受保护的父方法)。但是,可以做的是创建自己的调用方法!
class DecoratedService extends Service {
function call($method) {
if(!method_exists(parent, $method)) {
return false; // OR:
throw Exception;
// OR handle this case some other way
}
Log::start(array(parent, $method));
call_user_func(array(parent, $method));
Log::end(array(parent, $method));
}
}
$service = new DecoratedService;
$service->call('method1');
答案 1 :(得分:0)
我想,这是典型的智能参考模式(代理和装饰模式的混合)。
class A {
function test1() {
echo 'TEST 1', PHP_EOL;
}
function test2() {
echo 'TEST 1', PHP_EOL;
}
}
class ProxyA {
protected $wrapped;
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function __call($name, $args) {
echo 'Log:start';
$this->wrapped->$name($args);
echo 'Log:end';
}
}
$proxy = new ProxyA(new A());
$proxy->test1();
但它仅适用于公共方法。
将智能引用与来自@giorgio和@yceruto的DecoratedService :: call()方法混合可以覆盖所有方法,或者只实现两次__call():
class A {
public function test1() {
echo 'TEST 1', PHP_EOL;
}
private function test2() {
echo 'TEST 2', PHP_EOL;
}
public function __call($name, $args) {
if (method_exists($this, $name)) {
$this->$name($args);
}
}
}
class ProxyA {
protected $wrapped;
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function __call($name, $args) {
if (method_exists($this->wrapped, $name)) {
echo 'Log:start';
$this->wrapped->$name($args);
echo 'Log:end';
}
}
}
$proxy = new ProxyA(new A());
$proxy->test0(); // Nothing to do
$proxy->test1(); // Done
$proxy->test2(); // Done
答案 2 :(得分:-1)
使用magic __call方法可能会让您轻松:
class Service
{
public function test1() {
echo 'TEST 1', PHP_EOL;
}
protected function test2() {
echo 'TEST 2', PHP_EOL;
}
public function __call($method, $args) {
echo 'Some stuff before', PHP_EOL;
$returnValue = $this->$method($args);
echo 'Some stuff after', PHP_EOL;
return $returnValue;
}
}
$x = new Service();
$x->test2();
$x->test1();
请注意,如果可以从班级外部访问该方法(例如test1
),则不会调用__call()
;只有在涉及的方法受到保护或私有时才会执行;如果在对象内部调用