根据PHP 7返回类型提示已经有很多问题,以及如果将类定义为返回类型,为什么不能返回null.像这样:处理PHP 7返回类型的正确方法.答案通常说这不是一个问题,好像一个函数应该返回一个类然后返回null可能是一个例外.也许我错过了什么,但我真的不明白为什么.例如,让我们看一个简单的用户类:
class User
{
private $username; // mandatory
private $password; // mandatory
private $realName; // optional
private $address; // optional
public function getUsername() : string {
return $this->username;
}
public function setUsername(string $username) {
$this->username = $username;
}
public function getPassword() : string {
return $this->password;
}
public function setPassword(string $password) {
$this->password = $password;
}
public function getRealName() : string {
return $this->realName;
}
public function setRealName(string $realName = null) {
$this->realName = $realName;
}
public function getAddress() : Address {
return $this->address;
}
public function setAddress(Address $address = null) {
$this->address = $address;
}
}
Run Code Online (Sandbox Code Playgroud)
在我们的应用程序中,让用户没有realName和/或没有地址是完全合法的.我甚至可以将realName和address字段设置为null - 即使上面的解决方案不是最佳的.在我们的个人资料页面中,如果地址为空(空),我想显示提示.
但这只是一个例子.我们的应用程序有100多个数据库表和相应的PHP类,几乎所有这些都有可选字段.总是编写一个try catch块而不是简单地检查null来处理可选字段似乎对我来说有点不太理想.
那么上面的例子有什么好的解决方案呢?
问题是您的对象不遵循 OOP 规则。
首先,getter 和 setter 是邪恶的,因为它们暴露了对象的内部结构。您只需为系统的其余部分引入依赖内部用户对象结构的无限可能性。而对象的目的是隐藏实现细节并提供操作此隐藏数据的接口。
null是邪恶的(或者是十亿美元的错误),因为它使代码的可靠性大大降低。它引入了特殊情况(空返回值),并且有必要在使用对象的代码中处理这种特殊情况。更糟糕的是,如果您忘记处理这种“null”特殊情况(或者您不知道存在特殊情况),您将不会立即收到错误。因此,您将得到隐藏的错误,查找和修复该错误可能非常耗时。
实际上,我看到以下选项(在所有情况下 - 删除吸气剂):
选项 1) 以某种统一的形式获取配置文件数据的快照
$user->getProfileData() {
return [
'username': $this->username,
'realName': $this->realName ? $this->realName : '',
'address': $this->address ? $this->address : 'Not specified'
...
];
}
Run Code Online (Sandbox Code Playgroud)
这仍然是一种 getter,但是您将所有数据转换为统一的形式(字符串)。即使数据库中有一些整数的浮点字段(例如年龄或身高),您仍然会在此处返回字符串,因此系统的其余部分不依赖于对象的实际内部结构。
可选字段的空字符串(或特殊值,如“未指定”)也充当一种“空对象”。还可以将返回值包装到小字段对象中,并实际上对可选字段使用空对象模式。
在使用该类的代码中,您不应该处理特殊的“null”情况,您只需循环字段并显示字符串(包括那些为空的字符串)。
选项 2) 让对象本身负责呈现
$user->showProfile($profileView) {
$profileView->addLabel('First Name');
$profileView->addString($this->username);
...
}
Run Code Online (Sandbox Code Playgroud)
在这里,您将内部细节保留在对象内部,但现在它做得太多了,所以有人可能会说它现在违反了SRP。
选项 3)创建负责演示的特殊对象
$userPresentation = $user->createPresentation()
// internally it will return new UserPresentation($this->username, this->realName, $this->address, ...);
// now display it - generate the template and insert it into the view
<? echo $userPresentation->getHtml(); ?>
Run Code Online (Sandbox Code Playgroud)
在这里,您将表示逻辑移动到单独的对象中。用户对象和它的表示是紧密耦合的,但是系统的其余部分现在对用户对象的内部一无所知(也没有机会知道)。