Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP OOP类和函数_Php_Oop - Fatal编程技术网

PHP OOP类和函数

PHP OOP类和函数,php,oop,Php,Oop,我不知道该如何命名,但它在这里。让我们假设我有以下几点 class A { public function aa() { $this->bb(); } public function bb() { } } class B extends a { } class C { __construct(B $service) { $this->service = $service; } public func

我不知道该如何命名,但它在这里。让我们假设我有以下几点

class A {
    public function aa() {
       $this->bb();
    }
    public function bb() {

    }
}

class B extends a {

}

class C {
   __construct(B $service) {
       $this->service = $service;
   }
   public function aa() {

       $this->service->aa();
   }
}
我的呼叫代码将是

$C = new C(new B());
$C->aa();
这将基本上执行
A:aa()
,这就是我想要的。如您所见,在
A::aa()
中调用了
aa::bb()

我需要什么。当AA::bb()被调用时,我想执行C类中定义的一些代码,但不允许更改A类。我只能换B班或C班

我的想法是在B类中添加一个侦听器,然后像这样覆盖bb()函数

class B extends a {
    public $listener;
    bb() {
       parent::bb();
       $this->listener();
    }
}

class C {
   __construct(B $service) {
       $this->service = $service;
   }
   public function aa() {

       $this->service->listener = function() { }
       $this->service->aa();
   }
}
但我不太喜欢这个主意,看起来不是个好主意。我的选择是什么

同样,我不能更改A类,只能调用C类


PHP版本是5.3,您有两个选择。延伸或装饰

第一个是您已经写过的,不过,我不会对听众使用
public
visibility:

class Foo extends A {
    private $listener;
    public function setListener(callable $func) {
        $this->listener = $func;
    }
    public function bb() {
        call_user_func($this->listener);
        return parent:bb();
    }
}
在本例中,我通过setter注入传递了侦听器,但您也可以使用构造函数注入,并在重载的
\uu construct()
方法中传递
$listed
。扩展类时,“接口限制”不适用于构造函数的签名


另一种方法是使用装饰器:

class Foo {
    private $target;
    public function __construct(A $target) {
        $this->target = $target;
    }

    public function bb($callback) {
        $callback();
        return $this->target->bb();
    }

    public function __call($method, $arguments) {
        return call_user_func_array( 
                array( $this->target, $method ),
                $arguments
            );
    }
}
第二种方法可以让您更改接口


选择哪个选项取决于实际需要实现的确切功能。装饰器是一种解决方案,当您需要对对象行为进行重大更改时,例如,它非常适合添加访问控制。

我知道您希望在
a
中的代码完成后在
C
中执行代码。你不能改变

如前所述,
C::aa
调用
A::aa
,它调用
A::bb
,堆栈展开。为什么不在服务调用完成后在
C::aa
中进行工作

class C {
   public function aa() {
       $this->service->aa();
       // whatever you want to do
   }
}
另一方面,如果您需要在调用
A::aa
之后但在调用
A::bb
之前调用代码,那么您发布的示例就足够清晰了:

class B extends a {
    public $listener;
    public function bb() {
       call_user_func($this->listener);
       parent::bb();
    }
}

请注意使用了
call\u user\u func
,这是PHP5.3调用存储在成员变量中的匿名函数所必需的。

由于不能将侦听器逻辑直接保存在类B中,因此没有太多选项。我将
$this->service->listener=function(){}
移动到构造函数tho。你为什么不喜欢它?谢谢你的回答。我从问题中忽略的是,必须执行的代码需要在C类内部。在您的示例中,Foo是B类还是C类?它是
B
类。。你模糊的类/方法没有真正的帮助