在__construct中完成后调用一个方法

时间:2015-03-19 13:00:51

标签: php oop

基本上我有一个方法,我需要在构造函数完成时运行(该方法被称为persist(),它只是将构造函数中生成的密钥保存到会话中)。它似乎很简单,并且它有效 - 在__construct结束时,我调用$ this-> persist()。

问题是这个类多次被子类化。这会导致两个问题。

一,我必须记住在每个子类的__construct方法的末尾调用persist()。这不是一个很大的问题,但它并没有感觉到非常OOP,我觉得我可以在父类中处理这个问题,这样做会更好。

二,如果子类是子类(它是),并且链接的__construct方法(即调用了父:: __构造),则persist()方法将被多次触发,每次类被触发一次子类。所有施工完成后,只需要调用一次。在这种情况下,它并没有真正破坏任何东西,因为当第二次,第三次等调用持久化方法时,它只是覆盖之前持久化的内容。但这不是重点,因为我觉得必须有更好的方法,并且有些场景不允许多次调用该方法。

是一个构造对象的工厂方法,然后以唯一的方式使调用持久化吗?我可以沿着这条路走下去,但我只是想知道是否有办法在没有这条路的情况下做到这一点,以便在构建之后总是调用父方法。

以下是一些示例代码:

session_start();
is(!isset($_SESSION["Component"])) $_SESSION["Component"] = [];

abstract Class Component
{
    private $id;
    protected $key;

    function __construct($id = NULL)
    {
        $this->id = $id;
        $this->key = [];
        $this->key["something"] = "SomeValue";
        $this->persist(); // First call
    }

    protected function persist()
    {
        if($this->id !== NULL) $_SESSION["Component"][$this->id] = $this->key;
    }
}

Class SomeComponent extends Component
{
    function __construct($id = NULL)
    {
        parent::__construct($id);
        $this->key["something-else"] = "SomeOtherValue";
        $this->persist(); // Second call
    }
}

Class SomeSpecialistComponent extends SomeComponent
{
    function __construct($id = NULL, $key = [])
    {
        parent::__construct($id);
        $this->key = array_merge($this->key, $key);
        $this->persist(); // Third call
    }
}

$my_component = new SomeSpecialistComponent(1, ["example" => true]);

3 个答案:

答案 0 :(得分:2)

我发现只有一些类似的技巧(除了我想在之前而不是之后执行的东西)是使用带有抽象方法的父类作为新的构造函数:

abstract class RequireThings {

    public function __construct() {
        $this->constructAndPersist();
        $this->persist();
    }

    abstract function constructAndPersist();

    // You could also set this function in your children classes by the way.
    public function persist() {
        echo ' Then I persist!';    
    }


}

class UsingPersist extends RequireThings {

    public function constructAndPersist() {
        echo 'I do my things first.';
    }

}

$class = new UsingPersist();

输出:

I do my things first. Then I persist!

如果我的问题得到解决,应该足以避免您遇到的问题。

这个解决方案的主要缺点是你必须使用一个新函数,它应该是这类类的新构造函数。这就是我将__constructPersist设置为抽象的原因,它强制了所需的行为。

答案 1 :(得分:1)

在$ this->之前创建另一个您调用的函数,并在子类而不是构造函数中覆盖它并将其覆盖

答案 2 :(得分:1)

我会支持工厂方法,主要是因为你是doing real work in the constructor。删除构造函数($this->persist)中正在进行工作的调用并将其放在工厂中:

class ComponentFactory
{
    const SOME_COMPONENT = 'component';
    const SOME_SPECIALIST_COMPONENT = 'specialist_component';

    public static function make($type, $id, $key = null)
    {
        switch($type) {
            case self::SOME_COMPONENT:
                $component = new SomeComponent($id);
                break;
            case self::SOME_SPECIALIST_COMPONENT:
                $component = new SomeSpecialistComponent($id, $key);
                break;
        }

        $component->persist();
        return $component;
    }
}

$component = ComponentFactory::make(ComponentFactory::SOME_COMPONENT, 42);
$specialist = ComponentFactory::make(
    ComponentFactory::SOME_SPECIALIST_COMPONENT, 
    43, 
    [
        'something' => 'SomeValue', 
        'something-else' => 'SomeOtherValue',
    ]
);

根据MiškoHevery(AngularJS的作者和谷歌的敏捷教练),这些是在构造函数中做太多工作的警告信号:

  
      
  1. 构造函数或字段声明中的新关键字
  2.   
  3. 构造函数或字段声明中的静态方法调用
  4.   
  5. 除了构造函数中的字段赋值之外的任何内容
  6.   
  7. 构造函数完成后对象未完全初始化(观察   out for initialize methods)
  8.   
  9. 构造函数中的控制流(条件或循环逻辑)
  10.   
  11. CL在构造函数中执行复杂的对象图构造   而不是使用工厂或建筑商
  12.   
  13. 添加或使用初始化块
  14.