在 PHP 中的构造函数中调用可重写的访问器和修改器方法是否可以接受

Is it acceptable to call overridable accessor and mutator methods within a constructor in PHP

在构造函数方面,由于 PHP 中缺少访问器和修改器,我试图通过创建名为 setX() 和 getX() 的方法来模拟相同的功能,如下所示:

<?php

class Example {
  protected $message; // Nullable

  public function setMessage (Message $message = NULL) {
    $this->message = $message;
  }

  public function getMessage () {
    return $this->message;
  }
}

?>

我了解到使用构造函数设置属性应该与使用访问器和修改器方法设置属性相同。

但这会导致与构造函数相关的问题,正如我在许多地方所读到的那样,您不应在构造函数中调用可覆盖方法,因为在对象构造期间调用可覆盖方法可能会导致使用未初始化的数据,导致运行时异常或意外结果。

我的问题是,是否适用相同的规则,因为您不应调用可重载的访问器和修改器方法,如下例所示:

<?php

class Example {
  protected $message; // Nullable

  public function __construct (Message $message = NULL) {
    $this->setMessage($message);
  }

  public function setMessage (Message $message = NULL) {
    $this->message = $message;
  }

  public function getMessage () {
    return $this->message;
  }
}

?>

我阅读此信息的来源包括:

是的,确实适用。只需将其中一个示例移植到 PHP,看看会发生什么:

<?php

class SuperClass {
  public function __construct() {
    $this->doLogic();
  }

  public function doLogic() {
    echo "This is superclass!";
  }
}

class SubClass extends SuperClass {
  private $color = null;

  public function __construct() {
    parent::__construct();
    $this->color = "Red";
  }

  public function doLogic() {
    echo "This is subclass! The color is: $this->color";
  }
}

$bc = new SuperClass();
$sc = new SubClass();

可能的解决方案

  1. make 方法private,即不可覆盖
  2. make 方法final,即不可覆盖
  3. 调用parent::__construct作为子构造函数中的最后一个语句

我觉得可以接受

当您无法t/won将方法设置为final时,别无他法 我知道可以防止这种情况发生。

我也这样做,如果有人决定延长 class 他有责任不破坏它。

这肯定比将 setter 逻辑复制到您的构造函数要好。

根据Ionuş G. Stan 所说的,这是不可接受的,应该使用以下解决方案:

<?php

class SuperClass {
  private $_color;

  public function __construct (Color $color) {
    $this->_setColor($color);
  }

  private function _setColor (Color $color) {
    $this->_color = $color;
  }

  public function setColor (Color $color) {
    $this->_setColor($color);
    echo "This is superclass! The color is: $this->_color";
  }
}

class SubClass extends SuperClass {
  private $_color = null;

  public function setColor (Color $color) {
    parent::setColor($color);
    echo "This is subclass! The color is: $this->_color";
  }
}