根据 PHP 7 返回类型提示以及如果将类定义为返回类型,为什么不能返回 null 已经有很多问题。就像这个:Correct way to handle PHP 7 return types . 答案通常说这不是问题,因为函数应该返回一个类,然后返回 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;
}
}
在我们的应用程序中,没有真实姓名和/或没有地址的用户是完全合法的。我什至可以将 realName 和 address 字段设置为 null - 即使上面的解决方案不是最佳的。在我们的个人资料页面中,如果地址为 null(空),我想显示一个提示。
但这只是 1 个示例。我们的应用程序有 100 多个数据库表和相应的 PHP 类,几乎所有的表都有可选字段。总是写一个 try catch block 而不是简单地检查 null 来处理可选字段对我来说似乎有点次优。
那么上面的例子有什么好的解决方案呢?
最佳答案
问题是您的对象不遵循 OOP 规则。
首先,getters and setters are evil因为它们暴露了对象的内部结构。您只是为系统的其余部分介绍了依赖内部用户对象结构的无限可能性。而对象的目的是隐藏实现细节并提供操作这些隐藏数据的接口(interface)。
和null is evil (或 a billion dollar mistake )因为它使代码的可靠性大大降低。 它引入了特殊情况(空返回值),并且有必要在使用您的对象的代码中处理这种特殊情况。 更糟糕的是,如果你忘记处理这个“null”的特例(或者你不知道有一个特例),你不会立即得到错误。 因此,您将获得隐藏的错误,查找和修复这些错误非常耗时。
实际上,我看到以下选项(在所有情况下 - 删除 getter):
选项 1)以某种统一形式获取配置文件数据的快照
$user->getProfileData() {
return [
'username': $this->username,
'realName': $this->realName ? $this->realName : '',
'address': $this->address ? $this->address : 'Not specified'
...
];
}
这还是getter的一种,只不过你把所有的数据都转化成了统一的形式(字符串)。即使您的数据库中有一些整数的浮点字段(如年龄或高度),您仍会在此处返回字符串,因此系统的其余部分不依赖于对象的实际内部结构。
可选字段的空字符串(或特殊值,如“未指定”)也充当一种“空对象”。也可以将返回值包装到小的字段对象中,并实际对可选字段使用空对象模式。
在使用该类的代码中,您不应该处理特殊的“空”情况,您只需遍历字段并显示字符串(包括那些为空的字符串)。
选项 2)让对象本身负责呈现
$user->showProfile($profileView) {
$profileView->addLabel('First Name');
$profileView->addString($this->username);
...
}
在这里你保留了对象内部的细节,但现在它做的太多了,所以有人会说它现在违反了 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(); ?>
在这里,您将表示逻辑移动到单独的对象中。用户对象及其表示紧密耦合,但系统的其余部分现在对用户对象的内部结构一无所知(也没有机会知道)。
关于PHP 7 返回类型提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36544084/