有没有办法在不必创建变量的情况下捕获异常?
Posted
技术标签:
【中文标题】有没有办法在不必创建变量的情况下捕获异常?【英文标题】:Is there a way to catch an Exception without having to create a variable? 【发布时间】:2011-06-16 18:04:44 【问题描述】:在 php 中,我有时会使用 try/catch 捕获一些异常:
try
...
catch (Exception $e)
// Nothing, this is normal
使用这种代码,我最终得到了变量$e
,它是无用创建的(大量资源),PHP_MD(PHP Mess Detector)由于未使用的变量而创建警告。
【问题讨论】:
不应将异常视为“正常”——无论它是否是异常。是什么引发了异常? 我正在测试模型在应该抛出异常的时候。所以我有空的 catch 块,因为我只想测试是否抛出了异常。 【参考方案1】:这就是异常的全部意义——您可以使用多个不同的 catch 块来捕获您想要处理的任何异常。异常的数据必须分配到某个地方,因此是变量。如果您真的不想看到这些警告,您可以在 catch 块内执行类似unset($e)
的操作...或禁用警告(通常是个坏主意)。
【讨论】:
【参考方案2】:没有。
在任何情况下,捕获异常而什么都不做通常是个坏主意;异常的存在正是为了迫使您处理异常情况(否则执行将中止),因此可以理解该语言不利于这样的用例。
【讨论】:
同时,当您可能只需要状态码时抛出异常通常是个坏主意。如果异常实际上是异常的,我们就不会看到这么多无用的 try/catch 块。特别是,每当出现网络问题时,许多网络实用程序都会抛出异常,这会破坏封装并且对程序员没有真正的帮助。当您是网络实用程序时,网络问题不应该例外,您应该能够在内部处理它。【参考方案3】:异常不仅仅用于特殊情况。
此场景实际上使用异常来确保用户已注销。在脚本的这一点上,找出应该修剪哪些数据是非常耗费资源的,因此实际上只修剪所有数据并捕获异常会更快。
try
GDS::$DB->exec('DELETE FROM sessions WHERE session_id = ' . session_id());
GDS::$DB->exec('DELETE FROM sessions WHERE user_id = ' . $this->data['user_id']);
catch(PDOException $ex)
session_regenerate_id(true);
setcookie('bis_[user_id]', 0, time() - 1, null, null, false, true);
setcookie('bis_[session_start]', 0, time() - 1, null, null, false, true);
setcookie('bis_[session_time]', 0, time() - 1, null, null, false, true);
【讨论】:
答案如何? 另外,如果第一个抛出,这将跳过第二个语句,这可能不是预期的。【参考方案4】:You can with 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
,则必须声明变量。
【讨论】:
【参考方案5】:我根本不同意 Marc B 和 Artefacto 的回答。在某些情况下,忽略捕获是更好的选择,甚至是唯一的选择。尤其是在使用外部库(您无法控制抛出哪些异常)和/或异步操作时。
例如:
我只想在文件不存在的情况下创建它。我正在使用外部 I/O 库。想象一下它有File::exists($fileName)
和File::create($fileName)
方法。
选项 1(如果可以省略捕获):
try
File::create($fileName);
// Go on with the rest of the code.
选项 2(没有 try/catch):
if (!File::exists($fileName))
File::create($fileName);
这里,选项 1 完全有效,因为选项 2 有两个重要问题:
-
如果多个线程同时运行并通过此代码段,则可能是线程 A 首先检查文件是否存在。接下来,线程 B 检查文件是否存在。他们都发现它不存在。线程 A 创建文件。线程 B 然后尝试再次创建它并抛出异常,即使您正在使用 if 检查。
库本身很可能已经执行了
!File::exists($fileName)
检查。因此,您正在浪费一个已经拨打的电话。
请注意,如果File::create
引发了其他可能出乎意料的异常,最好捕获这些异常。
结论
说某事从来没有是个好主意,几乎从来没有是个好主意。规则总是有例外(呵呵)。与任何约定或设计模式一样,它只是一个经验法则,旨在帮助经验不足的开发人员做出正确的决定。
【讨论】:
您至少应该记录发生的异常。在 catch 块中不做任何事情会在您的代码中创建“黑洞”——有些东西不工作,你不知道为什么——除了逐行运行调试器直到问题发生,你没有办法跟踪它。跨度> @superrafal 在我的示例中根本不是这种情况。我确切地知道抛出了什么异常,并想忽略它并继续前进。为什么每次发生无害且可预测的事情时我都需要记录?【参考方案6】:从 PHP 8 开始,可以使用非捕获捕获。
This is the relevant 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");
这样,对于一些异常详细信息不相关且异常类型已经提供所有必要上下文的边缘情况,可以在不创建新变量的情况下捕获异常。
【讨论】:
【参考方案7】:从 PHP 8.0 开始,它可以不带变量输入,但每个 Exception
的一般情况现在是 Throwable
。 Exception
类实现 Throwable
。
try
...
catch (CustomException)
// CustomException
catch (Throwable)
//All other classes implementing Throwable interface
【讨论】:
以上是关于有没有办法在不必创建变量的情况下捕获异常?的主要内容,如果未能解决你的问题,请参考以下文章