28

我正忙于创建一个应用程序,我想使用 PHP 7 返回类型。现在我在 php.net 上读到这是一个不允许返回的设计决定null

处理这个的正确方法是什么?

一种选择是 try...catch 块:

public function getMyObject() : MyObject
{ 
     return null;
}

try
{
    getMyObject();
}
catch(Exception $e)
{
    //Catch the exception
}

我对此感觉不太好,因为我的代码将是一个巨大的 try...catch 块,因为我需要为每个返回对象的方法编写一个 try...catch 块。

Null Object Pattern是一个很好的解决方案,但我不喜欢NullObject为我的应用程序中的每个对象创建一个。有正确的方法吗?

4

6 回答 6

27

如果您的代码期望返回一个类的实例,在这种情况下MyObject,但它没有,那么这确实是一个异常,应该这样处理。

但是,您应该自己抛出这个异常。

public function getMyObject() : MyObject
{
    throw new MyCustomException("Cannot get my object");
}

然后您可以捕获该特定异常并相应地继续。

于 2015-12-14T13:48:43.887 回答
6

我对此感觉不太好,因为我的代码将是一个巨大的 try/catch 块,因为我需要为每个返回对象的方法编写一个 try/catch 块。

另一种方法(使用您的代码)将始终检查返回的值,null以免因null用作对象而出错。

使用异常更有表现力,并且可以及早发现错误,这是一件好事。因此,要么确保您的方法始终返回一个对象,要么在它无法履行合同时抛出异常。否则返回类型没有实际价值。

于 2015-12-14T13:44:15.350 回答
6

您可以使用Option数据类型。

它是一种具有SomethingNothing作为包装值的类型。

您可以在此处找到更详细的描述,并在此处找到PHP 中的开放实现之一

PS请不要对这种逻辑使用异常、输出参数或附加方法,这是一个错误的工作工具。

于 2015-12-14T15:51:27.200 回答
3

目前这是不可能的,尽管如前所述,有一些 RFC 可能会解决未来版本的问题。

到目前为止,您的选择是:

1.从您的方法签名中删除返回类型:

public function getMyObject()
{ 
     return null;
}

2.抛出并捕获异常(根据@NiettheDarkAbsol 的回答):

public function getMyObject() : MyObject
{
    throw new MyCustomException("Cannot get my object");
}

3.重构为两种方法:

private $myObject;
//TODO think of a better method name
public function canGetMyObject() : bool
{
    $this->myObject = new myObject();
    return true;
}

public function getMyObject() : MyObject
{
    if(!$this->myObject){
        throw new MyCustomException("Cannot get my object");
    }
    return $this->myObject;
}

调用代码:

if($cls->canGetMyObject()){
    $myObject  = $cls->getMyObject();
}

4.使用bool返回类型和out参数:

public function tryGetMyObject(&$out) : bool
{
    $out = new myObject();
    return true;
}

调用代码:

$myObject = null;

if($cls->tryGetMyObject($myObject)){      
    $myObject->someMethod(); //$myObject is an instance of MyObject class
}

第 3 和第 4 选项仅在预期返回 null 且频繁出现的情况下才真正值得考虑,因此异常的开销是一个因素。可能你会发现这实际上并不经常适用,例外是前进的方向

于 2015-12-14T14:04:18.913 回答
2

从 PHP7.1 开始,您可以使用可为空的返回类型:

public function getMyObject(): ?MyObject {
  return null;
}

http://php.net/manual/en/migration71.new-features.php

于 2017-12-15T17:06:38.510 回答
0

我正要问同样的问题。我认为这没有多大意义。

如果我有以下示例代码来按名称查找用户:

<?php

class User
{
    protected $name;

    /**
     * User constructor.
     *
     * @param $name
     */
    public function __construct(string $name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getName() : string
    {
        return $this->name;
    }
}


function findUserByName(string $name, array $users) : User {
    foreach ($users as $user) {
        if ($user->getName() == $name) {
            return $user;
        }
    }

    return null;
}


$users = [
    new User('John'), new User('Daniel')
];

$user = findUserByName('John', $users);

echo $user->getName()."\n";

$user2 = findUserByName('Micheal', $users);

我想告诉 Php 我可以得到 User 或 null。现在我需要将它始终包装在 try catch 块中,在这种情况下我认为声明返回类型没有多大意义。另一方面,如果我的findUserByName函数很复杂,我可能会意外返回例如用户名而不是完整的用户对象,所以我想定义返回类型。

我认为更合理的是为函数定义多种返回类型。有时您创建返回一个对象或对象数组的函数,并且最好定义,该函数应该返回例如User或用户数组:User[]

在 OP 情况下(也是我的情况),我们可以将返回类型声明为User, null,它可以解决问题。

于 2015-12-14T17:32:16.850 回答