最佳实践:在 php-doc 中使用 @throws,以及如何处理它

Posted

技术标签:

【中文标题】最佳实践:在 php-doc 中使用 @throws,以及如何处理它【英文标题】:Best practices: Use of @throws in php-doc, and how it could be handle 【发布时间】:2013-03-13 07:46:51 【问题描述】:

假设我有一个类,其方法如下:

/*
 *
 * Loads the user from username.
 *
 * @param string $username The username
 *
 * @return UserInterface
 *
 * @throws userNotFoundException if the user is not found
 */
public function getUser($username)

    // someFunction return an UserInterface class if found, or null if not.
    $user = someFunction('SELECT ....', $username);
    if ($user === null) 
        throw new userNotFoundException();
    

    return $user

现在假设 someFunction 可能会因为 XYZ 原因抛出 InvalidArgumentException / RuntimeException / PDOException。我该怎么办? 还有什么不呢?

1 号

php-docs 中添加所有可能引发 someFunction 的异常。

/*
 *
 * Loads the user from username.
 *
 * @param string $username The username
 *
 * @return UserInterface
 *
 * @throws userNotFoundException if the user is not found
 * @throws InvalidArgumentException
 * @throws ...
 */

2号

添加一个 try-catch 块以确保该方法应仅在文档中引发异常

/*
 *
 * Loads the user from username.
 *
 * @param string $username The username
 *
 * @return UserInterface
 *
 * @throws userNotFoundException if the user is not found
 * @throws RuntimeException 
 */
public function getUser($username)

    try 
        $user = someFunction('SELECT ....', $username);
     catch (Exception $e) 
        throw new RuntimeException();
    

    if ($user === null) 
        throw new userNotFoundException();
    

    return $user

3 号

什么都别做。

【问题讨论】:

Number1 和 Number2 在文档方面有什么区别?您是在询问文档或处理异常的最佳实践吗? 【参考方案1】:

我个人会考虑将 @throws 视为类似于 Java 的已检查异常

这在 Java 中的工作方式是基本上可以抛出从 RuntimeException 继承的异常,而不必处理。任何其他类型的异常都必须有一个 try-catch 块来处理它们。这个处理代码必须在调用者中。

在 PHP 中基本上是这样的:

当方法具有@throws 注释时,您必须添加代码来处理其异常。

任何未提及的异常都是可选的,可在调用代码中处理。


现在,我自己并没有 100% 遵循这个原则。整个处理异常的事情有点取决于程序员的偏好,但这只是我认为如何以合理的方式处理它的一些想法。

【讨论】:

是的,我正在寻找“如何处理它”,谢谢分享!所以,我提供的原始代码应该没问题,对吧?如果someFunction抛出任何异常,应该由应用句柄处理 是的,看起来不错。但是,请记住,不应将异常用于控制流。我不知道您的代码是否只是一个示例,但在我看来,如果找不到用户将是您通常需要处理的常见场景 - 因此通过返回来明确说明会更有意义一个空值。【参考方案2】:

关于文档,如果函数显式抛出异常,那么它应该包含在函数的文档中。因此,对于每个throw 语句,PHP 文档中都应该有一个对应的@throws

关于处理,如果有一些操作在抛出异常时应该执行,那么就捕获它。否则,让它冒泡——只要有一个catch 声明稍后会处理它。

更新:

几年后,我改变了这样一种观点,即只有当异常仍然与模块的抽象级别相关时,才应该让异常“冒泡”而不加修改。应采用捕获和重新抛出策略以使异常更有意义。它还应该避免不必要地泄露有关抽象底层模块的信息,从而使错误处理更加安全。

/**
 * @throws UserNotFoundException
 */
public function getUser($username)

    try 
        $user = someFunction('SELECT ....', $username);
     catch (DatabaseException $dbe) 

        /* Re-throw since a database exception may no longer be
         * meaningful to the caller.
         */
        throw new UserNotFoundException();
    

    return $user

【讨论】:

您的更新很好,但我认为区分faults and contingencies 也是有益的,其中将记录意外事件,但不会记录故障。故障自然会冒泡到某种故障边界(例如,应用程序顶层),在那里它们会根据需要进行处理(转换、吞噬、记录、泄漏等)。 OTOH,意外事件构成模块接口的一部分,因此对调用者应该是有意义的。简单地冒泡突发事件是泄漏实现细节的一种形式。 @KenWayneVanderLinde 这是一个很好的观点!你所说的是对异常的更全面的看法,我完全同意。非常感谢分享这个!【参考方案3】:

从文档维护的角度来看,我只会为特别抛出的异常添加 @throw 行,否则您很快就会使您的文档过时。

【讨论】:

【参考方案4】:

第二个,但可能会在返回之前抛出,因为抛出动作将在返回之前发生......

【讨论】:

以上是关于最佳实践:在 php-doc 中使用 @throws,以及如何处理它的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 错误处理的最佳实践是啥?

关于JAVA异常处理的20个最佳实践

Atitit. 异常的使用总结最佳实践java .net php Vo8f

第12章 异常

在 .Net 中使用扩展方法的最佳实践是啥?

Java 数据绑定最佳实践