【问题标题】:Extended class pulling through NULL - OOP扩展类通过 NULL - OOP
【发布时间】:2018-04-15 23:15:08
【问题描述】:

我的所有用户方法都有以下类:

class User {
  protected $_db,
            $_data;

  public function __construct($user = null, $findby = 'id') {
    $this->_db = DB::getInstance();

    if (!$user) {
      ........
    } else {
      ........
    }
  }

 .......

  public function login($username = null, $password = null) {
    $user = $this->find($username, 'username');
    if ($user) {
      $lockdown = new Lockdown; 
    }
  }

  public function find($param = null, $method = null) {
    if ($param && $method) {
      $data = $this->_db->query("SELECT * FROM users ...");
      if ($data->count()) {
        $this->_data = $data->result();
        return true;
      }
    }
    return false;
  }

  public function data() {
    return $this->_data;
  } 
}

以上是我的用户类的完全精简版。我还有另一个扩展用户的类(锁定):

class Lockdown extends User {
  public $getAttempts;

  public function __construct() {
    var_dump($this->data());
    die();
  }
}

但是,当我在登录类中调用锁定类时,即使数据对象应该包含所有用户信息,var_dump() 也只是返回 NULL。

根据我调用登录类时的计算,find 方法 应该设置 $_data = USER INFO,因此应该允许在 ($this->find( )) 能够访问相同的数据方法。

我仍在学习 OOP 编程,所以不知道我是否缺少某些东西,但我似乎无法理解 Lockdown 类在应该继承它时在数据方法上返回 NULL 的原因。

【问题讨论】:

  • 嗨@mic,感谢您的回复。我已将 User::__construct() 类添加到原始问题中,并且看不到调用它如何帮助填充 _data 变量。请问为什么 _data 变量没有被填充,因为代码似乎表明应该在调用 Lockdown 之前执行 data 方法?
  • 在 Lockdown 的 __construct() 中,您需要在调用 var_dump 之前添加 parent::__construct()
  • 只要我将用户名提供给 __construct() 方法,parent::__construct() 就可以工作。现在所有的工作谢谢。然而还有一件更快捷的事情,为什么当我的方法都不是静态的时它是 parent::__construct()?
  • @MatthewM 你需要注意 tereško 的回答。
  • 传入$this作为构造函数参数?你是疯了还是只是妄想?

标签: php class oop extends


【解决方案1】:

您不应该将任何计算逻辑放在构造函数中。它使测试变得困难。您也不能从构造函数返回。

你的结构是一场彻底的灾难。都是因为您滥用继承和全局状态。

类创建自己的子类的新实例来检索数据是没有意义的。这可能是因为您试图让User 类结合两个不同的职责:持久性和业务逻辑。这构成了对Single Responsibility Principle 的违反,然后以复杂调用图的形式表现出来。

整个class Lockdown extends User 构造也没有任何意义。 OOP 中的extends 关键字可以翻译为“是特殊情况”(根据LSP)。跟踪用户登录尝试的类不是“用户”的特例。

为此,您应该至少有 3 个单独的类:一个用于处理“用户的行为”,另一个用于保存/恢复“用户的状态”(该方法称为“data mapper”)。第三个是用于管理失败的尝试。

我也强烈推荐观看this lecture

对于全局状态,你应该将数据库连接作为构造函数的依赖传递给需要与持久性交互的类,而不是使用单例反模式。

至于代码,在高层次上,它可能看起来像这样:

$user = new User;
$mapper = new UserMapper($db);

$user->setName($username)
if ($mapper->fetch($user)) {
   if ($user->matchPassword($password)) {
       // you have logged in
       // add some flag in session about it
       header('Location: /greetings');
       exit;
   }
   // check the failed attempts
} else {
  // no matching username 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多