PHP异常VS函数中的返回用法(最佳实践)

时间:2016-11-07 13:34:33

标签: php function exception return return-value

在我们的团队中,我们经常讨论函数VS中某些返回数组的异常使用情况,但我仍然不确定如何以正确的方式执行。因此,让我们尝试从头开始提问:

何时使用VS返回数组的异常,包含有关结果的所有信息?

示例#1

function doAwesomeStuff($foo) {

    // prepare return values...
    $result = [
        'success' => true,
        'infoMessage' => '',
        'stuffDetails' => []
    ];

    // check params...
    if (!is_numeric($foo)) {
        $result['success'] = false;
        $result['infoMessage'] = 'Something went wrong...';
        return $result;
    }

    // do something else...
    if ($somethingElseWentWrong) {
        $result['success'] = false;
        $result['infoMessage'] = 'Something else went wrong...';
        return $result;
    }

    // add new data...
    $result['stuffDetails'] = [
        'foo' => 'bar'
    ];

    // done...
    return $result;
}

$foo = 42;
$awesomeStuff = doAwesomeStuff($foo);
if ($awesomeStuff['success'] === false) {
    echo $awesomeStuff['infoMessage'];
    // some error handling stuff...
}

// do some other awesome stuff
// ...

示例2

function doAwesomeStuff($foo) {

    // prepare return value...
    $stuffDetails = [];

    // check params...
    if (!is_numeric($foo)) {
        throw new InvalidArgumentException('Something went wrong...');
    }

    // do something else...
    if ($somethingElseWentWrong) {
        throw new AnotherException('Something else went wrong...');
    }

    // add new data...
    $stuffDetails = [
        'foo' => 'bar'
    ];

    // done...
    return $stuffDetails;
}


try {

    $foo = 42;
    $awesomeStuff = doAwesomeStuff($foo);

    // do some other awesome stuff... 
    // ...without caring about error handling at this point (it's all done in catch blocks)

} catch InvalidArgumentException($e) {
    echo $e->getMessage();
    // some error handling stuff...
} catch AnotherException($e) {
    echo $e->getMessage();
    // some error handling stuff...
}

那么哪个版本更好"错误处理方式,#1还是#2?它只是一个品味的问题,还是两个版本之一的真正争论?

有一个简单的最佳实践"规则"用于告诉您在函数中具有单个退出点的方法或函数。这已经是答案,这意味着它将是v2?

我真的很感激所有关于这个话题的想法: - )

2 个答案:

答案 0 :(得分:2)

多年前,当我读到它时,我得到了很多关于这个问题的信息。首先,原则是“告诉,不要问”(herehere)以及完整的第3章和第7章“清洁代码”之后的罗伯特·C·马丁。

有了这个,你可以实现一些好的东西,以了解该方法应该和不应该做什么。

一种方法应该仅在询问或要求时才返回。询问某些东西的方法的前缀为:

  • get; //混合
  • has; //布尔
  • is; //布尔
  • can。 //布尔

或者,可以有单词return(不必作为前缀):

  • doSomethingAwesomeAndReturn。 //混合

名称create是一个例外,因为创建不必要的东西必须返回:

  • createSomethingAwesomeAndReturn。 //混合

如果您的方法没有任何相关内容,则不应返回任何内容。

在第3章中,您可以找到名为“首选返回错误代码的例外”的部分,在第7章中您可以找到“不要返回空”。这解释了因返回某些东西而产生的一些问题。很多验证链,空对象等......这些问题可以通过返回异常来解决。

你的第二个例子很好,但是就像方法名称所说的那样,它确实很棒,不应该返回。如果没有例外,那就做了很棒的事情。如果确实需要返回,则必须重构或至少重命名方法以匹配预期。

毕竟,指导您的编码只是一个很多建议,而不是一个不灵活的规则。

更新

我忘记了前缀add。这是一个例外。以add为前缀的方法应该返回相同的对象以匹配fluent interface,没有别的。作为Fluent界面,它不应该与上述规则相匹配,无论方法的名称/前缀/后缀如何,因为它只是为了流利而不是凝聚力。

答案 1 :(得分:1)

我建议#2使用例外,因为如果您使用返回值进行错误处理,则无法真正将其用于实际用途,并返回一些内容。此外,您可以使用预定义的异常类型或创建新的单独的异常类来区分异常并根据需要处理它们。

stackoverflow上还有其他人已经写好了关于例外或返回代码/错误的良好利弊: