如何在界面文档中记录@throws

2022-08-30 21:09:24

我正在编写一个PHP库,我有一个问题。我的界面中有类似于以下内容的内容:

<?php
/**
 * My interface
 *
 * ...
 */
interface MyInterface
{
    /**
     * This method does foo.
     *
     * @throws \RuntimeException If foo can't be done.
     */
    public function fooAndBar();
}
?>

现在,该条目并不完全正确,因为接口实际上不执行任何操作,并且纯粹用于抽象实现细节。但是,我一直使用它,因为我的所有接口实现都会在出现问题时引发异常。@throws

但是另一个开发人员可能会编写一个不会失败的实现(因此它不会引发异常),或者他/她可能想要使用另一个异常类。

在这种情况下,我应该如何在接口声明中进行文档记录?它甚至应该被记录下来吗?@throws


答案 1

考虑使用接口的代码:

public function doSomething(MyInterface $my) { ... }

如果其中一个实现可以引发异常,则需要确保处理异常的可能性。

所以,是的,它应该被记录下来。

即使只有一个实现引发异常,仍然需要进行异常处理。当然,这并不意味着每种方法都应该有一个@throws。它仍然应该只在适当的时候使用(当你期望一个实现合法地需要抛出一个异常时)。

作为一个更具体的例子,请考虑以下几点:

interface LogWriter
{

    /**
     * @throws LogWriterException
     */
    public function write($entry);

}


class DbLogWriter
{

    public function __construct(PDO $db)
    {
        //store $db somewhere
    }

    public function write($entry)
    {
        try {
            //store $entry in the database
        } catch (PDOException $e) {
            throw new LogWriterException(...);
        }
    }

}

class NullLogWriter
{
    public function write($entry) { }
}

在写入数据库时,可以执行某些操作来尝试降低异常的可能性,但归根结底,这不是异常安全操作。因此,应该预期会引发异常。DbLogWriter::write

现在考虑空编写器,它只是丢弃条目。那里绝对没有任何东西会出错,因此,不需要例外。

然而,如果你有一些,你所知道的只是它是 的实现。你是假设它不会抛出异常,并可能意外地让一个冒泡,还是假设它可以抛出一个?我会保持安全,并假设它可以抛出LogWriterException。$logLogWriterLogWriterException

如果用户只知道是 LogWriter,但只有 DbLogWriter 被记录为引发异常,则用户可能没有意识到可以引发异常。此外,当稍后创建FileLogWriter时,这将意味着已经设置了实现可以并且可能引发的异常的期望(没有人会期望抛出一个)。$log$log->write(...)FileLogWriterRandomNewException


答案 2

接口定义协定。实现类是否引发异常是 PHP 中的实现细节,因为方法签名中没有关键字(如 Java)。添加注释不能在技术上强制执行协定,但它可以指示约定(顺便说一句,返回值也是如此)。这是否足够好,由您决定。throws@throws

顺便说一句,如果开发人员提出了一个不会抛出你的实现,那么你就不会有问题,因为无论如何你都必须为那些确实抛出的实现添加一个try/catch块(按照惯例)。如果一个实现开始抛出与DocBlock中指示的不同异常,那将是一个问题,因为这样它就不会被捕获。


推荐