← 返回目录

第二章:基础语法

变量、类型、数组与控制流

2.1 变量与常量

变量基础

PHP 变量以 $ 符号开头,无需声明类型即可使用。变量名区分大小写。

<?php
// 变量无需声明,直接赋值即可
$name = "张三";
$age = 28;
$price = 99.5;
$isActive = true;

// 变量名规则:以字母或下划线开头,后跟字母、数字、下划线
$_privateVar = "合法";
$camelCase = "推荐的命名风格";

// 可变变量(少用,但要知道)
$varName = "hello";
$$varName = "world";   // 等价于 $hello = "world"
echo $hello;           // 输出: world

常量

常量一旦定义不可修改。推荐使用 const(编译时)或 define()(运行时)。

<?php
// 方式一:const(推荐,编译时定义,可用于类中)
const APP_VERSION = "2.0.0";
const MAX_RETRY = 3;

// 方式二:define()(运行时定义,可用于条件语句中)
define('DB_HOST', 'localhost');
define('FEATURES', ['login', 'register', 'profile']); // 数组常量

// 使用常量(不需要 $ 符号)
echo APP_VERSION;  // 2.0.0
echo DB_HOST;      // localhost

// 魔术常量(双下划线开头和结尾)
echo __FILE__;     // 当前文件完整路径
echo __LINE__;     // 当前行号
echo __DIR__;      // 当前文件所在目录
echo __FUNCTION__; // 当前函数名
echo __CLASS__;    // 当前类名

变量作用域

<?php
$globalVar = "我是全局变量";

function testScope(): void {
    // echo $globalVar;  // ❌ 报错!函数内无法直接访问全局变量

    // 方式一:global 关键字
    global $globalVar;
    echo $globalVar;     // ✅ 可以了

    // 方式二:$GLOBALS 超全局数组
    echo $GLOBALS['globalVar']; // ✅ 也可以

    // 局部变量
    $localVar = "我是局部变量";

    // 静态变量:函数调用结束后保留值
    static $count = 0;
    $count++;
    echo "调用次数: $count";
}

testScope(); // 调用次数: 1
testScope(); // 调用次数: 2
testScope(); // 调用次数: 3

🔄 与 Python / JavaScript 对比

特性 PHP Python JavaScript
变量前缀 $name name let name
需要声明 是(let/const/var)
常量 const / define() 无原生常量(约定大写) const
函数作用域 默认隔离全局 可读全局,写需 global 闭包/块级作用域

2.2 数据类型

类型一览

分类 类型 示例 说明
标量 int 42, 0xFF, 0b1010, 1_000_000 整数,支持十六进制、二进制、下划线分隔
float 3.14, 1.2e3 浮点数(双精度)
string "hello", 'world' 字符串
bool true, false 布尔值(大小写不敏感)
复合 array [1, 2, 3] 有序映射(兼具列表和字典功能)
object new stdClass 类的实例
特殊 null null 空值,变量未赋值时的默认值
可调用 callable fn($x) => $x * 2 函数、闭包或可调用对象

类型检测与转换

<?php
$val = "42";

// 检测类型
echo gettype($val);          // string
echo get_debug_type($val);   // string(PHP 8.0+,更精确)
var_dump($val);               // string(2) "42"

// 类型判断函数
is_int($val);      // false
is_string($val);   // true
is_numeric($val);  // true(字符串 "42" 是数字)
is_null($val);     // false
is_array($val);    // false

// 类型转换(强制)
$intVal = (int) "42";       // 42
$floatVal = (float) "3.14"; // 3.14
$strVal = (string) 100;     // "100"
$boolVal = (bool) "";       // false
$arrVal = (array) "hello";  // ["hello"]

// intval() / floatval() / strval() 函数形式
$num = intval("0xFF", 16);  // 255,第二参数指定进制

PHP 8.x 类型声明

<?php
// 基本类型声明
function add(int $a, int $b): int {
    return $a + $b;
}

// 可空类型(参数可以传 null)
function findUser(?int $id): ?array {
    if ($id === null) {
        return null;
    }
    return ['id' => $id, 'name' => '张三'];
}

// 联合类型(PHP 8.0+)
function formatId(int|string $id): string {
    return "ID: $id";
}

// 交叉类型(PHP 8.1+)
function process(Iterator&Countable $collection): void {
    foreach ($collection as $item) {
        echo $item;
    }
}

// DNF 类型(PHP 8.2+,组合联合与交叉)
function handle((Iterator&Countable)|null $data): void {
    // ...
}

// 返回 never(PHP 8.1+,函数永不返回)
function throwError(string $msg): never {
    throw new RuntimeException($msg);
}

// 返回 void(无返回值)
function logMessage(string $msg): void {
    echo "[LOG] $msg\n";
}

// strict_types 严格模式(文件级别)
declare(strict_types=1);
// 开启后 add("3", "4") 将抛出 TypeError(不再自动转换)

2.3 字符串操作

单引号 vs 双引号

<?php
$name = "张三";
$age = 25;

// 双引号:支持变量插值和转义序列
echo "你好,$name!\n";                // 你好,张三!
echo "年龄:{$age}岁\n";               // 年龄:25岁
echo "花括号用于复杂表达式:{$user['name']}\n";

// 单引号:原样输出(性能略好)
echo '你好,$name!\n';               // 你好,$name!\n(原样输出)

// 字符串拼接用 .(点号),不是 +
$greeting = "你好," . $name . "!";
$greeting .= " 欢迎光临。";           // .= 追加赋值

Heredoc 与 Nowdoc

<?php
$name = "张三";

// Heredoc:类似双引号,支持变量插值
$html = <<<HTML
<div class="card">
    <h2>{$name} 的主页</h2>
    <p>欢迎来到我的网站</p>
</div>
HTML;

// Nowdoc:类似单引号,不解析变量
$template = <<<'TPL'
Hello, $name!
这里不会做变量替换。
TPL;

echo $html;     // 变量被替换
echo $template; // 原样输出 $name

常用字符串函数

<?php
$str = "  Hello, PHP World!  ";

// 长度与查找
echo strlen($str);                    // 23(含空格)
echo mb_strlen("你好世界");            // 4(多字节安全)
echo strpos($str, "PHP");             // 9(返回位置,0 起始)
echo str_contains($str, "PHP");       // true(PHP 8.0+)
echo str_starts_with($str, "  He");   // true(PHP 8.0+)
echo str_ends_with($str, "!  ");      // true(PHP 8.0+)

// 截取
echo substr($str, 9, 3);             // "PHP"
echo mb_substr("你好世界", 0, 2);     // "你好"

// 分割与合并
$parts = explode(",", "a,b,c,d");    // ["a", "b", "c", "d"]
$joined = implode(" | ", $parts);    // "a | b | c | d"

// 替换
echo str_replace("PHP", "Laravel", $str);  // "  Hello, Laravel World!  "
echo str_ireplace("php", "Laravel", $str); // 不区分大小写替换

// 格式化
echo sprintf("用户: %s, 年龄: %d, 余额: %.2f", "张三", 25, 1234.5);
// 用户: 张三, 年龄: 25, 余额: 1234.50

// 清理
echo trim($str);                     // "Hello, PHP World!"(去除两端空白)
echo ltrim($str);                    // 去除左侧
echo rtrim($str);                    // 去除右侧

// 大小写转换
echo strtolower("HELLO");            // "hello"
echo strtoupper("hello");            // "HELLO"
echo ucfirst("hello world");         // "Hello world"
echo ucwords("hello world");         // "Hello World"

// 其他常用
echo str_repeat("=-", 20);           // 重复字符串
echo str_pad("42", 5, "0", STR_PAD_LEFT);  // "00042"
echo nl2br("第一行\n第二行");          // "第一行<br />\n第二行"

💡 多字节字符串

处理中文等多字节字符时,务必使用 mb_ 前缀的函数(如 mb_strlenmb_substr),否则可能得到错误的长度或截断结果。确保 php.ini 中设置了 mbstring.internal_encoding = UTF-8

2.4 数组(PHP 最核心的数据结构)

PHP 数组是有序映射(ordered map),它同时充当了列表、字典、集合、栈、队列等多种数据结构的角色。这是 PHP 最重要也是使用最频繁的类型。

🔄 与 Python / JavaScript 对比

PHP 的 array ≈ Python 的 list + dict 的合体。一个 PHP 数组既可以当索引列表用([1, 2, 3]),也可以当关联字典用(['name' => '张三']),甚至可以混用。JavaScript 中类似的概念是 Array + Object,但 PHP 数组的功能更统一。

创建数组

<?php
// 索引数组(类似 Python list)
$fruits = ["苹果", "香蕉", "橙子"];
$numbers = [1, 2, 3, 4, 5];

// 关联数组(类似 Python dict)
$user = [
    'name' => '张三',
    'age'  => 28,
    'email' => 'zhangsan@example.com',
];  // 末尾逗号是允许的(推荐写法)

// 多维数组
$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];

// 复杂嵌套
$users = [
    ['name' => '张三', 'age' => 28, 'skills' => ['PHP', 'MySQL']],
    ['name' => '李四', 'age' => 32, 'skills' => ['Go', 'Docker']],
];

// 访问元素
echo $fruits[0];           // "苹果"
echo $user['name'];        // "张三"
echo $users[0]['skills'][1]; // "MySQL"

// 修改与添加
$fruits[] = "葡萄";        // 追加到末尾
$fruits[0] = "红苹果";     // 修改第一个
$user['phone'] = '13800138000'; // 添加新键

// 删除元素
unset($fruits[1]);         // 删除索引 1(注意:不会重新索引)
$fruits = array_values($fruits); // 重新索引

解构赋值

<?php
// 索引数组解构
[$a, $b, $c] = [10, 20, 30];
echo $b; // 20

// 跳过元素
[, , $third] = [10, 20, 30];
echo $third; // 30

// 关联数组解构
$user = ['name' => '张三', 'age' => 28, 'city' => '北京'];
['name' => $name, 'age' => $age] = $user;
echo "$name, $age"; // 张三, 28

// 在 foreach 中解构
$points = [['x' => 1, 'y' => 2], ['x' => 3, 'y' => 4]];
foreach ($points as ['x' => $x, 'y' => $y]) {
    echo "($x, $y) ";  // (1, 2) (3, 4)
}

Spread 运算符

<?php
// 合并数组(PHP 7.4+)
$first = [1, 2, 3];
$second = [4, 5, 6];
$merged = [...$first, ...$second]; // [1, 2, 3, 4, 5, 6]

// 关联数组 spread(PHP 8.1+)
$defaults = ['color' => 'blue', 'size' => 'M'];
$custom = ['size' => 'L', 'weight' => '200g'];
$config = [...$defaults, ...$custom];
// ['color' => 'blue', 'size' => 'L', 'weight' => '200g']

// 用于函数参数展开
function sum(int ...$nums): int {
    return array_sum($nums);
}
$numbers = [1, 2, 3, 4, 5];
echo sum(...$numbers); // 15

常用数组函数

<?php
$arr = [3, 1, 4, 1, 5, 9, 2, 6];

// ---- 基础操作 ----
echo count($arr);              // 8(元素个数)
echo in_array(5, $arr);        // true(是否存在)
echo array_search(4, $arr);    // 2(查找位置)

$user = ['name' => '张三', 'age' => 28];
echo array_key_exists('name', $user); // true
$keys = array_keys($user);     // ['name', 'age']
$vals = array_values($user);   // ['张三', 28]

// ---- 增删改 ----
array_push($arr, 7);          // 末尾添加 → [..., 7]
array_pop($arr);               // 弹出末尾
array_unshift($arr, 0);       // 头部添加
array_shift($arr);             // 弹出头部
$sliced = array_slice($arr, 2, 3); // 从索引2取3个
array_splice($arr, 2, 1, [40, 50]); // 替换:删1个,插入2个

// ---- 合并与组合 ----
$merged = array_merge([1, 2], [3, 4]);       // [1, 2, 3, 4]
$combined = array_combine(['a', 'b'], [1, 2]); // ['a'=>1, 'b'=>2]
$unique = array_unique([1, 2, 2, 3, 3]);      // [1, 2, 3]
$flipped = array_flip(['a' => 1, 'b' => 2]);  // [1 => 'a', 2 => 'b']

// ---- 排序(原地修改) ----
$nums = [3, 1, 4, 1, 5];
sort($nums);       // [1, 1, 3, 4, 5]   值排序,重新索引
rsort($nums);      // [5, 4, 3, 1, 1]   值逆序
asort($nums);      // 值排序,保留键名
ksort($nums);      // 按键排序

// 自定义排序
$items = ['banana', 'apple', 'cherry'];
usort($items, fn($a, $b) => strcmp($a, $b)); // 字母序

函数式操作

<?php
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// array_map:对每个元素执行操作,返回新数组
$doubled = array_map(fn($n) => $n * 2, $numbers);
// [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

// array_filter:过滤,保留回调返回 true 的元素
$evens = array_filter($numbers, fn($n) => $n % 2 === 0);
// [2, 4, 6, 8, 10](注意:保留原始键名)

// array_reduce:归约
$sum = array_reduce($numbers, fn($carry, $n) => $carry + $n, 0);
// 55

// array_walk:遍历并修改(原地)
$prices = ['apple' => 5, 'banana' => 3, 'cherry' => 8];
array_walk($prices, function(&$price, $name) {
    $price = $price * 1.1; // 加价 10%
});

// array_column:从多维数组中提取一列
$users = [
    ['id' => 1, 'name' => '张三', 'dept' => '技术'],
    ['id' => 2, 'name' => '李四', 'dept' => '产品'],
    ['id' => 3, 'name' => '王五', 'dept' => '技术'],
];
$names = array_column($users, 'name');         // ['张三', '李四', '王五']
$nameById = array_column($users, 'name', 'id'); // [1=>'张三', 2=>'李四', 3=>'王五']

2.5 控制流

条件判断

<?php
$score = 85;

// if / elseif / else
if ($score >= 90) {
    echo "优秀";
} elseif ($score >= 70) {
    echo "良好";
} elseif ($score >= 60) {
    echo "及格";
} else {
    echo "不及格";
}

// 三元运算符
$status = $score >= 60 ? "通过" : "未通过";

// 短三元(Elvis 运算符)
$displayName = $username ?: "匿名用户";  // $username 为假值时用默认值

// null 合并运算符(后面详细讲)
$name = $_GET['name'] ?? '游客';

match 表达式(PHP 8.0+)

matchswitch 的现代替代品,使用严格比较(===),且是表达式(有返回值)。

<?php
$statusCode = 404;

// match 表达式:简洁、严格比较、有返回值
$message = match($statusCode) {
    200 => '成功',
    301 => '永久重定向',
    302 => '临时重定向',
    400 => '错误请求',
    401 => '未授权',
    403 => '禁止访问',
    404 => '页面未找到',
    500 => '服务器错误',
    default => '未知状态码',
};
echo $message; // "页面未找到"

// 多值匹配
$lang = 'zh-CN';
$greeting = match($lang) {
    'zh-CN', 'zh-TW' => '你好',
    'en-US', 'en-GB' => 'Hello',
    'ja' => 'こんにちは',
    default => 'Hi',
};

// 无参数 match(替代 if-elseif 链)
$score = 85;
$grade = match(true) {
    $score >= 90 => 'A',
    $score >= 80 => 'B',
    $score >= 70 => 'C',
    $score >= 60 => 'D',
    default => 'F',
};

💡 match vs switch

match 使用严格比较 ===,不需要 break,并且是表达式可以赋值。如果没有匹配且没有 default,会抛出 UnhandledMatchError。建议在 PHP 8+ 项目中优先使用 match 替代 switch

循环

<?php
// for 循环
for ($i = 0; $i < 5; $i++) {
    echo $i; // 0 1 2 3 4
}

// while 循环
$count = 0;
while ($count < 3) {
    echo $count++;
}

// do-while(至少执行一次)
$input = '';
do {
    $input = readline("输入 'quit' 退出: ");
} while ($input !== 'quit');

// foreach —— PHP 中最常用的循环
$colors = ['red', 'green', 'blue'];

// 遍历值
foreach ($colors as $color) {
    echo $color;
}

// 遍历键值对
$user = ['name' => '张三', 'age' => 28, 'city' => '北京'];
foreach ($user as $key => $value) {
    echo "$key: $value\n";
}

// 通过引用修改元素
$prices = [10, 20, 30];
foreach ($prices as &$price) {
    $price *= 1.1; // 每个价格加 10%
}
unset($price); // ⚠️ 务必 unset 引用变量,否则后续代码可能出错

// 嵌套遍历多维数组
$users = [
    ['name' => '张三', 'skills' => ['PHP', 'MySQL']],
    ['name' => '李四', 'skills' => ['Go', 'Redis']],
];
foreach ($users as $user) {
    echo "{$user['name']} 的技能: ";
    foreach ($user['skills'] as $skill) {
        echo "$skill ";
    }
    echo "\n";
}

// 循环控制
for ($i = 0; $i < 10; $i++) {
    if ($i === 3) continue; // 跳过 3
    if ($i === 7) break;    // 到 7 停止
    echo $i; // 0 1 2 4 5 6
}

2.6 运算符

算术与赋值运算符

<?php
// 算术
$a = 10;
$b = 3;
echo $a + $b;   // 13   加
echo $a - $b;   // 7    减
echo $a * $b;   // 30   乘
echo $a / $b;   // 3.33 除
echo $a % $b;   // 1    取模
echo $a ** $b;  // 1000 幂运算

// 复合赋值
$x = 10;
$x += 5;   // $x = $x + 5 → 15
$x -= 3;   // 12
$x *= 2;   // 24
$x /= 4;   // 6
$x %= 4;   // 2
$x **= 3;  // 8
$x .= "px"; // "8px"(字符串拼接赋值)

// 自增自减
$i = 5;
echo $i++;  // 5(先返回再自增)
echo ++$i;  // 7(先自增再返回)

比较运算符

⚠️ 必须掌握:== 与 === 的区别

PHP 的 ==(宽松比较)会做类型转换,这导致了许多令人困惑的行为。强烈建议始终使用 ===(严格比较)

<?php
// == 宽松比较(会类型转换,各种坑)
var_dump(0 == "foo");      // PHP 8: false(PHP 7 是 true!)
var_dump("" == false);     // true
var_dump("0" == false);    // true
var_dump(null == false);   // true
var_dump("" == null);      // true
var_dump(0 == null);       // true
var_dump("1" == true);     // true
var_dump("123" == 123);    // true

// === 严格比较(类型和值都必须相同)
var_dump(0 === false);     // false(int vs bool)
var_dump("" === false);    // false(string vs bool)
var_dump("123" === 123);   // false(string vs int)
var_dump(null === false);  // false(null vs bool)

// ✅ 经验法则:永远用 === 和 !==

逻辑运算符

<?php
$a = true;
$b = false;

echo $a && $b;  // false   与(短路求值)
echo $a || $b;  // true    或(短路求值)
echo !$a;       // false   非

// and / or 优先级低于 && / ||,不建议混用
// 推荐始终使用 && || !

Null 相关运算符

<?php
// null 合并运算符 ??(PHP 7.0+)
// 左侧为 null 或未定义时使用右侧值
$name = $_GET['name'] ?? '游客';
$config = $settings['timeout'] ?? $defaults['timeout'] ?? 30;

// null 合并赋值 ??=(PHP 7.4+)
$data['count'] ??= 0; // 等价于 $data['count'] = $data['count'] ?? 0;

// null 安全运算符 ?->(PHP 8.0+)
// 对象为 null 时不报错,直接返回 null
$user = getUser(42); // 可能返回 null
$city = $user?->getAddress()?->getCity();
// 等价于:$city = ($user !== null && $user->getAddress() !== null)
//              ? $user->getAddress()->getCity() : null;

太空船运算符

<?php
// 太空船运算符 <=>(PHP 7.0+)
// 返回 -1(小于)、0(等于)、1(大于)
echo 1 <=> 2;   // -1
echo 2 <=> 2;   //  0
echo 3 <=> 2;   //  1

// 常用于排序回调
$users = [
    ['name' => '张三', 'age' => 28],
    ['name' => '李四', 'age' => 22],
    ['name' => '王五', 'age' => 35],
];
usort($users, fn($a, $b) => $a['age'] <=> $b['age']);
// 按年龄升序:李四(22) → 张三(28) → 王五(35)

// 多字段排序
usort($users, fn($a, $b) =>
    $a['age'] <=> $b['age'] ?: $a['name'] <=> $b['name']
);

2.7 错误处理

try / catch / finally

<?php
try {
    $result = riskyOperation();
    echo "结果: $result";
} catch (InvalidArgumentException $e) {
    echo "参数错误: " . $e->getMessage();
} catch (RuntimeException $e) {
    echo "运行时错误: " . $e->getMessage();
} catch (Exception $e) {
    echo "其他异常: " . $e->getMessage();
} finally {
    echo "无论是否异常都会执行(清理资源等)";
}

// 联合捕获(PHP 8.0+)
try {
    processInput($data);
} catch (TypeError | ValueError $e) {
    echo "输入错误: " . $e->getMessage();
}

// 仅捕获不使用变量(PHP 8.0+)
try {
    json_decode($json, flags: JSON_THROW_ON_ERROR);
} catch (JsonException) {
    echo "JSON 解析失败";
}

异常层次结构

<?php
// PHP 内置异常层次
// Throwable
// ├── Error              (引擎级错误,通常不捕获)
// │   ├── TypeError
// │   ├── ValueError      (PHP 8.0+)
// │   ├── ArithmeticError
// │   │   └── DivisionByZeroError
// │   └── ...
// └── Exception          (应用级异常)
//     ├── RuntimeException
//     ├── InvalidArgumentException
//     ├── LogicException
//     ├── OverflowException
//     └── ...

// 自定义异常
class BusinessException extends RuntimeException
{
    public function __construct(
        string $message,
        private readonly string $errorCode,
        int $code = 0,
        ?\Throwable $previous = null,
    ) {
        parent::__construct($message, $code, $previous);
    }

    public function getErrorCode(): string
    {
        return $this->errorCode;
    }
}

class InsufficientBalanceException extends BusinessException {}

// 使用自定义异常
function withdraw(float $amount, float $balance): float
{
    if ($amount <= 0) {
        throw new InvalidArgumentException("取款金额必须大于 0");
    }
    if ($amount > $balance) {
        throw new InsufficientBalanceException(
            "余额不足",
            errorCode: 'INSUFFICIENT_BALANCE',
        );
    }
    return $balance - $amount;
}

try {
    $newBalance = withdraw(500, 100);
} catch (InsufficientBalanceException $e) {
    echo "{$e->getMessage()} (错误码: {$e->getErrorCode()})";
    // 余额不足 (错误码: INSUFFICIENT_BALANCE)
}

全局错误处理

<?php
// 将传统 PHP 错误转为异常
set_error_handler(function (int $severity, string $message, string $file, int $line): bool {
    if (!(error_reporting() & $severity)) {
        return false;
    }
    throw new ErrorException($message, 0, $severity, $file, $line);
});

// 全局异常处理器(兜底)
set_exception_handler(function (Throwable $e): void {
    error_log("未捕获的异常: {$e->getMessage()} 在 {$e->getFile()}:{$e->getLine()}");
    if (php_sapi_name() === 'cli') {
        echo "致命错误: {$e->getMessage()}\n";
    } else {
        http_response_code(500);
        echo "<h1>服务器内部错误</h1>";
    }
});

// 关闭函数(捕获致命错误)
register_shutdown_function(function (): void {
    $error = error_get_last();
    if ($error !== null && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR])) {
        error_log("致命错误: {$error['message']}");
    }
});

2.8 本章要点

💲 变量与常量

  • • 变量用 $ 前缀,无需声明类型
  • const 定义编译时常量,define() 定义运行时常量
  • • 函数内默认无法访问全局变量(需 global

🏷️ 类型系统

  • • PHP 8.x 支持完整类型声明:联合类型、交叉类型、nullable
  • declare(strict_types=1) 启用严格模式
  • • 多字节字符串用 mb_ 系列函数

📦 数组

  • • PHP 数组 = 有序映射,兼具列表和字典功能
  • array_maparray_filterarray_reduce 实现函数式操作
  • • Spread 运算符 ... 用于合并和展开

🔀 控制流

  • match 表达式替代 switch,严格比较有返回值
  • foreach 是遍历数组的首选
  • • 引用遍历后务必 unset 引用变量

⚖️ 运算符

  • 始终用 === 而不是 ==
  • ?? null 合并、?-> null 安全调用
  • <=> 太空船运算符简化排序

🛡️ 错误处理

  • try/catch/finally + 自定义异常层次
  • • PHP 8: 联合捕获 catch (A | B $e)
  • set_error_handler 将传统错误转为异常

掌握了基础语法后,下一章将学习 函数与面向对象编程 —— PHP 8.x 的类系统功能丰富,是现代 PHP 开发的基石。