【问题标题】:Correct way to handle PHP 7 return types处理 PHP 7 返回类型的正确方法
【发布时间】:2016-03-19 23:52:09
【问题描述】:

我正忙于创建应用程序,我想使用 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 的想法。 有正确的方法吗?

【问题讨论】:

  • 返回false?简单的数据类型,仍然清楚它未能初始化对象。
  • php 7.1 接受了 void 返回类型。所以它会在未来出现。
  • 明智的解决方案是确保getMyObject 返回实际对象。看起来您的对象可能处于次优的无效状态。但是在不了解您的代码的情况下很难猜测。
  • void 返回类型与本案例无关
  • 我真的不明白这个问题,但不管它可能是什么:你永远不应该随便捕获Error 异常。除非您有一些非常特殊的情况,否则您的应用程序应该只在一个地方捕获这些:顶级异常处理程序。我认为您在这里寻找的是简单地省略类型注释。这仍然是允许的。如果您的返回是“object or null”,那么这就是您应该做的(直到我们引入可空类型)。

标签: php oop php-7


【解决方案1】:

如果您的代码希望返回一个类的实例,在本例中为 MyObject,但它没有返回,那么这确实是一个异常,应该这样处理。

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

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

然后您可以捕获该特定异常并进行相应处理。

【讨论】:

  • 有没有办法拥有特定对象的数组:像public function getMyObject() : Array[MyObject]
【解决方案2】:

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

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

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

【讨论】:

  • 你说的很有道理。也许避免 try/catch 块是一种习惯,但我认为这是接受这种行为并利用它的好处的好时机。
  • 如果 Null 对象没有意义(通常是这种情况),添加第二个方法 hasMyObject() 是有意义的,您可以在实际获取它之前检查它。这是最明确的方法。
【解决方案3】:

您可以使用Option 数据类型。

这是一种将SomethingNothing 作为包装值的类型。

您可以找到更详细的描述 here 和 PHP here 中的开放实现之一

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

【讨论】:

【解决方案4】:

目前这是不可能的,尽管如前所述,有 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 且频繁出现的情况下才真正值得考虑,因此异常开销是一个因素。 可能你会发现这实际上并不经常适用,例外是前进的方向

【讨论】:

  • 从不同的答案中我觉得最好的方法是抛出自定义异常。我会尝试一下,希望开销值得这些优势!
  • 是的,这可能是真的,上面的其他选项仅适用于特定情况,有些人会认为例外是最好的解决方案。请注意,我添加了第四种方法,您可能更喜欢第三种方法
【解决方案5】:

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

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

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

【讨论】:

    【解决方案6】:

    我也想问。我认为这没什么意义。

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

    <?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,这样就可以解决问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-22
      • 2013-12-08
      • 1970-01-01
      • 2020-09-07
      • 1970-01-01
      • 2017-04-10
      相关资源
      最近更新 更多