«

PHP finally

时间:2025-5-12 15:11     作者:wanzi     分类: php


我以为我理解try ... catch ...finally 中finally  ,但是我死去的学习记忆还有死倔的特质让我造成了线上致命bug

事故现场

朋友找我说:“你的登录接口怎么一直是用户名或密码错误”,把我搞懵了,幸亏这是个人的产品。我休息了片刻去调试,发现确实如此,然后在那里耽误了半个小时才改好。

一开始我的代码是:

 try {
   if (!$user) {
       return $this->fail('用户名或密码错误');
    }

  $result = $this->authService->login($authDto);
 return $this->success('授权成功')
 } catch (\Throwe $e) {
    Logger::error("[授权失败]用户xxx在xx设备授权失败,原因:{$e->getMessage()}");
    return $this->fail('用户名或密码错误');
 }

然后我又改了:

 // ...
 try {
   if ($user) {
     $result = $this->authService->login($authDto);
      return $this->success('授权成功')
    }
 } catch (\Throwe $e) {
    Logger::error("[授权失败]用户xxx在xx设备授权失败,原因:{$e->getMessage()}");
    //return $this->fail('用户名或密码错误');
 } finally {
  return $this->fail('用户名或密码错误');
}

改过的代码后,我也没测了,因为没改之前测试过了,内心笃定了finally的理解。结果我错了,现在想来我有去注意这个finally的含义和作用吗?好像n年前有看过鸟哥的网站介绍又好像没有看过。

finally解说

在 PHP 中使用 try ... catch ... finally 结构时,即使在 try 或 catch 块中执行了 return,finally 块中的代码仍然会执行 。

这是 PHP(以及 Java、C# 等语言)设计的一个特性:

finally 块总会被执行(除非程序提前终止,如 exit() 或崩溃),不管是否发生了异常或是否有 return 语句。

示例说明:

function test() {
    try {
        echo "In try\n";
        return "Returned from try\n";
    } catch (Exception $e) {
        echo "In catch\n";
    } finally {
        echo "In finally\n";
    }
}

echo test();

输出结果:

In try
In finally
Returned from try

为什么这样设计?

finally 的目的是用来做资源清理 的工作,比如关闭文件、数据库连接、释放锁等。无论函数是否提前返回或者抛出异常,这些资源都应该被正确释放。

function readFile($filename) {
    $handle = fopen($filename, 'r');
    try {
        $content = fread($handle, filesize($filename));
        return $content;
    } finally {
        fclose($handle);
        echo "File handle closed.\n";
    }
}

即使读取文件后立即 return,也要确保 fclose 被调用。

特殊情况注意:
如果 finally 中也包含 return,那么它将覆盖 try 或 catch 中的返回值:

function test() {
    try {
        return "from try";
    } finally {
        return "from finally";
    }
}

echo test(); // 输出: from finally

所以要注意:finally 中的 return 会覆盖前面的返回值。