PHP语法高级篇(五):回调函数与异常处理

在 PHP 编程中,回调函数与异常处理是提升代码灵活性与健壮性的关键技术。回调函数能极大增强代码的复用性与扩展性;而异常处理则帮助开发者捕获并妥善处理运行时错误,避免程序意外崩溃。本篇文章将记录过回调函数与异常处理的学习过程。


一、回调函数

回调函数(通常简称为"回调")是一个作为参数传递给另一个函数的函数。函数是以 string 形式传递的。可以使用任何内置或用户自定义函数(从 PHP 7 版本开始,回调参数也接受匿名函数),但除了语言结构,例如:array(),echo,empty(),eval(),exit(),isset(),list(),print 或 unset()。

示例 将回调函数传递给 PHP 的 array_map() 函数,将数组中每个字符串转换为大写

php 复制代码
// array_map:为数组的每个元素应用回调函数

// 回调函数,将数组中每个字符串转换为大写
function my_callback($item) {
    return strtoupper($item);
}

$strings = ["apple", "orange", "banana"];
$upper_strings = array_map('my_callback', $strings);
print_r($upper_strings);

示例 从用户定义的函数中运行回调函数

php 复制代码
// 回调函数
function my_callback() {
    echo 'Hello World!';
}

// 自定义函数,接受回调函数
function custom($callback) {
    $callback();
}

// 调用自定义函数 custom(),将回调函数 my_callback() 作为参数传入
custom("my_callback");

二、异常处理

PHP 有一个和其他语言相似的异常模型。在 PHP 里可以 throw 并捕获(catch)异常。为了捕获潜在的异常,代码会包含在 try 块里。每个 try 都必须至少有一个相应的 catch 或 finally 块。

如果抛出异常的函数作用域内没有 catch 块,异常会沿调用栈"向上冒泡",直到找到匹配的 catch 块。沿途会执行所有遇到的 finally 块。在没有设置全局异常处理程序时,如果调用栈向上都没有遇到匹配的 catch,程序会抛出 fatal 错误并终止。

示例 抛出一个异常

php 复制代码
function divide($dividend, $divisor) {
    if($divisor == 0) {
        // throw 语句允许用户定义的函数或方法抛出异常
        throw new Exception("除数不能为0");
    }
    return $dividend / $divisor;
}

echo divide(1, 0);

上述示例输出:

异常对象(Exception)包含有关函数遇到的错误或意外行为的信息。

语法

php 复制代码
new Exception(message, code, previous)

参数

|----------|--------------------------------------------|
| message | 可选。描述为何抛出异常的字符串。 |
| code | 可选。整数,可用于轻松区分同一类型的不同异常。 |
| previous | 可选。如果此异常是在另一个异常的 catch 块中抛出的,建议将此异常传递给此参数。 |

当捕获异常时,下表显示了一些可用于获取有关异常信息的方法:

|---------------|-------------------------------------------|
| 方法 | 描述 |
| getMessage() | 返回描述为何抛出异常的字符串。 |
| getPrevious() | 如果此异常是由另一个异常触发的,此方法返回前一个异常。如果不是,则返回 null。 |
| getCode() | 返回异常代码。 |
| getFile() | 返回抛出异常的文件的完整路径。 |
| getLine() | 返回抛出异常的代码行的行号。 |

1、try...catch 语句

catch 定义了处理抛出异常的方式。 catch 块定义了它能处理的异常/错误的类型,并可以选择将异常赋值到变量中。如果遇到抛出对象的类型匹配了首个 catch 块的异常或错误,将会处理该对象。

可用多个 catch 捕获不同的异常类。正常情况下(try 代码块里没有抛出异常)会在最后一个定义的 catch 后面继续执行。 catch 代码块里也可以 throw 或者重新抛出异常。不抛出的话,会在触发的 catch 后面继续执行。

当 PHP 抛出一个异常时,将不会执行后续的代码语句,并会尝试查找首个匹配的 catch 代码块。如果没有用 set_exception_handler() 设置异常处理函数, PHP 会在异常未被捕获时产生 Fatal 级错误,提示 "Uncaught Exception ..." 消息。

从 PHP 7.1.0 起 catch 可以用竖线符(|) 指定多个异常。如果在不同的类层次结构中,不同的异常需要用同样的方式处理,就特别适用这种方式。

语法

php 复制代码
try {
  可能抛出异常的代码
} catch(Exception $e) {
  当捕获到异常时运行的代码
}

示例 捕获并处理异常

php 复制代码
function divide($dividend, $divisor) {
    if($divisor == 0) {
        // throw 语句允许用户定义的函数或方法抛出异常
        throw new Exception("除数不能为0");
    }
    return $dividend / $divisor;
}

try {
    echo divide(1, 0);
} catch (Exception $e) {
    echo "出现错误,无法执行";
}
// 程序执行,输出 "出现错误,无法执行"

catch 块指示应该捕获哪种类型的异常以及用于访问异常的变量名称。在上面的示例中,异常的类型是 Exception,变量名称是 $e。

2、try...catch...finally 语句

finally 代码块可以放在 catch 之后,或者直接代替它。无论是否抛出了异常,放在 finally 里的代码总是会执行。

值得注意的是 finally 和 return 语句之间存在相互影响。如果在 try 或 catch 里遇到 return,仍然会执行 finally 里的代码。而且,遇到 return 语句时,会先执行 finally 再返回结果。此外,如果 finally 里也包含了 return 语句,将返回 finally 里的值。

示例 添加 finally 代码块

php 复制代码
function divide($dividend, $divisor) {
    if($divisor == 0) {
        // throw 语句允许用户定义的函数或方法抛出异常
        throw new Exception("除数不能为0");
    }
    return $dividend / $divisor;
}

try {
    echo divide(1, 0);
} catch (Exception $e) {
    echo "出现错误,无法执行<br>";
} finally {
    echo "总会执行";
}
// 程序执行,输出:
/*
出现错误,无法执行
总会执行
*/

3、全局异常处理程序

当允许异常冒泡到全局作用域时,它可以被全局异常处理器捕获到。 set_exception_handler() 可以设置一个函数,在没有调用其它块时代替 catch。在本质上,实现的效果等同于整个程序被 try-catch 包裹起来。

php 复制代码
set_exception_handler(?callable $callback): ?callable

设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。在 callback 调用后异常会中止。

参数

callback:当一个未捕获的异常发生时所调用的函数。该处理函数需要接受一个参数,该参数是抛出的 Throwable 对象。也可以传递 null 值用于重置异常处理函数为默认值。

返回值

返回之前定义的异常处理程序,或者在错误时返回 null。如果之前没有定义错误处理程序,也会返回 null。

示例

php 复制代码
function exception_handler(Throwable $e) {
    $code = $e->getCode();
    $message = $e->getMessage();
    $file = $e->getFile();
    $line = $e->getLine();
    echo "在文件 $file 的第 $line 行抛出了异常:[代码 $code] <br>$message";
}

set_exception_handler('exception_handler');

throw new Exception('异常');
echo "未执行";
相关推荐
ServBay9 小时前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户9623779544812 小时前
CTF 伪协议
php
BingoGo3 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack3 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo4 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack4 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack5 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo5 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack6 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理6 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php