扩展 class 通过 NULL 拉取 - OOP
Extended class pulling through NULL - OOP
我的所有用户方法都有以下 class:
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 的完全精简版。我还有另一个 class (锁定)扩展用户:
class Lockdown extends User {
public $getAttempts;
public function __construct() {
var_dump($this->data());
die();
}
}
然而,当我在登录 class 中调用锁定 class 时,即使数据对象应包含所有用户信息,var_dump() 也只是返回 NULL .
根据我在调用登录 class 时的计算,find 方法 应该设置 $_data = USER INFO,因此应该允许调用新的 Lockdown 方法在 ($this->find()) 之后能够访问相同的数据方法。
我仍在学习 OOP 编程,所以不知道我是否遗漏了什么,但我似乎无法理解锁定的原因 class returns NULL关于数据方法何时应该继承它。
您不应该在构造函数中放置任何计算逻辑。这使得测试变得困难。您也不能从构造函数中 return 。
你的结构完全是一场灾难。都是因为您滥用了继承和全局状态。
class 创建其自己的子 class 的新实例来检索数据是没有意义的。这可能是您尝试 User
class 结合两种不同职责的结果:持久性和业务逻辑。这构成了对 Single Responsibility Principle 的违反,然后以复杂的调用图的形式表现出来。
此外,整个 class Lockdown extends User
结构毫无意义。 OOP 中的 extends
关键字可以翻译为 "is special case of"(根据 LSP)。用于跟踪用户登录尝试的 class 不是 "user" 的特例。
你应该至少有 3 个单独的 classes:一个用于处理 "user's behavior",另一个用于 saving/restoring "user's state"(这种方法称为“data mapper").第三个将用于管理失败的尝试。
我也强烈推荐观看 this lecture。
至于全局状态,而不是使用单例反模式,您应该将数据库连接作为构造函数的依赖项传递给需要与持久性交互的class。
至于代码,在较高层次上,它可能看起来像这样:
$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
}
我的所有用户方法都有以下 class:
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 的完全精简版。我还有另一个 class (锁定)扩展用户:
class Lockdown extends User {
public $getAttempts;
public function __construct() {
var_dump($this->data());
die();
}
}
然而,当我在登录 class 中调用锁定 class 时,即使数据对象应包含所有用户信息,var_dump() 也只是返回 NULL .
根据我在调用登录 class 时的计算,find 方法 应该设置 $_data = USER INFO,因此应该允许调用新的 Lockdown 方法在 ($this->find()) 之后能够访问相同的数据方法。
我仍在学习 OOP 编程,所以不知道我是否遗漏了什么,但我似乎无法理解锁定的原因 class returns NULL关于数据方法何时应该继承它。
您不应该在构造函数中放置任何计算逻辑。这使得测试变得困难。您也不能从构造函数中 return 。
你的结构完全是一场灾难。都是因为您滥用了继承和全局状态。
class 创建其自己的子 class 的新实例来检索数据是没有意义的。这可能是您尝试 User
class 结合两种不同职责的结果:持久性和业务逻辑。这构成了对 Single Responsibility Principle 的违反,然后以复杂的调用图的形式表现出来。
此外,整个 class Lockdown extends User
结构毫无意义。 OOP 中的 extends
关键字可以翻译为 "is special case of"(根据 LSP)。用于跟踪用户登录尝试的 class 不是 "user" 的特例。
你应该至少有 3 个单独的 classes:一个用于处理 "user's behavior",另一个用于 saving/restoring "user's state"(这种方法称为“data mapper").第三个将用于管理失败的尝试。
我也强烈推荐观看 this lecture。
至于全局状态,而不是使用单例反模式,您应该将数据库连接作为构造函数的依赖项传递给需要与持久性交互的class。
至于代码,在较高层次上,它可能看起来像这样:
$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
}