繁体   English   中英

PHP 7返回类型提示

[英]PHP 7 return type hinting

根据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;
    }

}

在我们的应用程序中,让用户没有realName和/或没有地址是完全合法的。 我甚至可以将realName和address字段设置为null - 即使上面的解决方案不是最佳的。 在我们的个人资料页面中,如果地址为空(空),我想显示提示。

但这只是一个例子。 我们的应用程序有100多个数据库表和相应的PHP类,几乎所有这些都有可选字段。 总是编写一个try catch块而不是简单地检查null来处理可选字段似乎对我来说有点不太理想。

那么上面的例子有什么好的解决方案呢?

问题是您的对象不遵循OOP规则。

首先, getter和setter是邪恶的,因为它们暴露了对象的内部结构。 您只需介绍依赖于系统其余部分的内部用户对象结构的无限可能性。 虽然该对象的目的是隐藏实现细节并提供操作此隐藏数据的接口。

null是邪恶的 (或十亿美元的错误 ),因为它使代码更不可靠。 它介绍了特殊情况(null返回值),并且必须在使用您的对象的代码中处理这种特殊情况。 更糟糕的是,如果你忘记处理这个“空”特殊情况(或者如果你不知道有特殊情况),你将不会立即得到错误。 因此,您将获得隐藏的错误,这可能非常耗时,无法找到并修复。

实际上,我看到以下选项(在所有情况下 - 删除getter):

选项1)以统一的形式获取配置文件数据的快照

$user->getProfileData() {
    return [
        'username': $this->username,
        'realName': $this->realName ? $this->realName : '',
        'address': $this->address ? $this->address : 'Not specified'
        ...
    ];
}

这仍然是一种吸气剂,但您将所有数据转换为统一形式(字符串)。 即使数据库中有一些浮点字段的整数(如年龄或高度),您仍然会在此处返回字符串,因此系统的其余部分不依赖于对象的实际内部。

可选字段的空字符串(或类似“未指定”的特殊值)也充当一种“空对象”。 也可以将返回的值包装到小字段对象中,并实际使用空对象模式作为可选字段。

在使用该类的代码中,您不应该处理特殊的“null”情况,只需循环遍历字段并显示字符串(包括那些空字符串)。

选项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(); ?>

在这里,您将表示逻辑移动到单独的对象中。 用户对象和它的表示是紧密耦合的,但系统的其余部分现在对用户对象内部结构一无所知(并且没有机会知道)。

我最近接受了这样的想法,即null 意味着存在问题 ,所以我知道当我看到它时,它意味着出了问题。

在这些情况下,我倾向于使用Null对象设计模式
因此,要处理地址,您将创建类似于:

class NullAddress implements AddressInterface { }

Address类还需要实现AddressInterface
然后, getAddress()看起来像:

public function getAddress(): AddressInterface {
    return $this->address ?? new NullAddress();
}

然后,调用getAddress()函数可以通过以下方式检查null值:

if ($user->getAddress() instanceof NullAddress) {
    // Implement result of empty address here.
}

为了处理字符串,到目前为止返回的空字符串对我很有帮助。 我只是使用empty()来检查它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM