最佳实践:在 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,以及如何处理它的主要内容,如果未能解决你的问题,请参考以下文章