有没有一种方法可以在不创建变量的情况下捕获异常?

57

在 PHP 中,我有时会使用 try/catch 来捕获一些异常:

try {
    ...
} catch (Exception $e) {
    // Nothing, this is a test that an exception is thrown.
}

使用这种代码,我最终得到了一个毫无意义的变量$e(大量资源),而且PHP_MD(PHP混乱检测器)会因为未使用的变量而创建一个警告。

6个回答

39

从PHP 8开始,可以使用非捕获catch语句。

这是相关RFC,得到48-1的赞成投票。

现在将可以像这样操作:

try {
    readFile($file);
} catch (FileDoesNotExist) {
    echo "File does not exist";
} catch (UnauthorizedAccess) {
    echo "User does not have the appropriate permissions to access the file";
    log("User attempted to access $file");
}

通过这种方式,在某些边缘情况下,如果异常细节不相关且异常类型已经提供所有必要的上下文,就可以在不创建新变量的情况下捕获异常。


你能提供一些关于如何在没有“Throw”的情况下工作的教育文档吗?我正在检查我的常用位置,但它们都是为<8.0制作的。 - jpgerb
@jpgerb 显然,需要在某个地方使用throw。这里假设readFile()throw任何异常,因此被包裹在一个try/catch块中。 - undefined

20

您可以使用 PHP 8 @see

PHP 5、7

不行,但您可以取消设置它。

try {
    ...
} catch (Exception $e) {
    // Nothing, this is normal
    unset($e);
}

如果是PHPMD引起了这个问题,那么你可以抑制警告。

PHPMD suppress-warnings

class Bar {
    /**
     * This will suppress UnusedLocalVariable
     * warnings in this method
     *
     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
     */
    public function foo() {

        try {
            ...
        } catch (Exception $e) {
            // Nothing, this is normal
            unset($e);
        }
    }
}

我假设您只是因为需要而不是想要才捕获异常。 在 PHP 5、7 中,如果您想使用 try ,就必须使用 catch ,如果您使用了 catch ,就必须声明一个变量。


8

这就是异常的全部意义 - 你可以有多个不同的catch块来捕获任何你想要处理的异常。异常的数据必须被分配到某个地方,因此需要一个变量。如果你真的不想看到这些警告,你可以在catch块内做一些类似于unset($e)的操作... 或者禁用警告(通常不是一个好主意)。


1
在编程中,有一些合理的情况下,不必对异常数据进行任何处理。 - James

8
我基本上不同意Marc B和Artefacto的回答。有些情况下,省略try-catch块可能更好,甚至是唯一的选择,尤其是在使用外部库(你无法控制抛出哪些异常)和/或异步操作时。
例如:
我想只在文件不存在时创建一个文件。我正在使用外部I/O库。假设它有File::exists($fileName)和File::create($fileName)方法。
选项1(如果可以省略try-catch):
try {
    File::create($fileName);
}
// Go on with the rest of the code.

选项2(不使用try/catch):

if (!File::exists($fileName))
    File::create($fileName);

在这里,选项1是完全有效的,因为选项2有两个重要问题:
  1. 如果有多个线程同时运行并通过此代码部分,则可能会发生线程A首先检查文件是否存在。接下来,线程B检查文件是否存在。他们都发现它不存在。线程A创建文件。然后,线程B再次尝试创建它并抛出异常,即使您使用if检查。
  2. 很可能库本身已经执行了!File :: exists($ fileName)检查。因此,您正在浪费已经进行的调用。
请注意,如果File :: create引发其他可能意外的异常,则最好捕获这些异常。
结论
声明某些事情从来不是一个好主意,几乎从来不是一个好主意。总有例外(嘿嘿)的规则。像任何约定或设计模式一样,它只是一个拇指规则,旨在帮助经验不足的开发人员做出正确的决策。

你至少应该记录下异常的发生。在 catch 块中不做任何事情会在代码中创建“黑洞”——某些东西不起作用,而你不知道为什么——除了逐行运行调试器直到问题出现之外,没有其他方法可以追踪它。 - superrafal
2
@superrafal 这并不是我例子中的情况。我清楚地知道抛出了什么异常,并希望忽略它并继续执行。为什么每次发生无害和可预测的事情时都需要记录日志呢? - Wouter Florijn

7

不行。

无论如何,捕获异常后什么也不做通常都是一个坏主意;异常存在的目的就是为了强制你处理异常情况(否则执行将被中止),因此理解语言不支持这种用例。


6
同时,通常情况下,如果你只需要一个状态码,就抛出异常是不太好的做法。如果异常确实很少见,我们就不会看到那么多无用的try/catch块了。特别是,许多网络工具在遇到网络问题时都会抛出异常,这破坏了封装性,并没有真正帮助程序员。对于网络工具来说,网络问题不应该是异常情况,应该能够在内部处理它。 - Roger Halliburton

2

PHP 8.0开始,可以不使用变量对其进行类型化,但每个Exception的一般情况现在是Throwable。类Exception实现了Throwable

try {
    ...
} catch (CustomException) {
    // CustomException
} catch (Throwable) {
    //All other classes implementing Throwable interface
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接