在 finished __construct 之后调用一个方法

Call a method after __construct in finished

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

问题是这个 class 被 subclass 编辑了很多次。这会导致两个问题。

第一,我必须记住在每个子class 的__construct 方法结束时调用persist()。这不是一个大问题,但感觉不是很 OOP,我觉得我可以在父级中处理这个问题 class 一些如何并且这会更好。

两个,如果 subclass 被 subclassed(确实如此),并且 __construct 方法被链接(即调用 parent::__construct),则持久化() 方法将被触发多次,每次 class 被 subclassed 一次。当所有构造完成时,它只需要调用一次。在这种情况下,它并没有真正破坏任何东西,因为当第 2 次、第 3 次等调用 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]);

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

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

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!

如果我解决了你的问题,应该足以避免你面临的问题。

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

我赞成工厂方法,主要是因为您 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ško Hevery(AngularJS 的作者和 Google 的敏捷教练)的说法,这些是在构造函数中做太多工作的警告信号:

  1. new keyword in a constructor or at field declaration
  2. Static method calls in a constructor or at field declaration
  3. Anything more than field assignment in constructors
  4. Object not fully initialized after the constructor finishes (watch out for initialize methods)
  5. Control flow (conditional or looping logic) in a constructor
  6. CL does complex object graph construction inside a constructor rather than using a factory or builder
  7. Adding or using an initialization block