PHP 8 新特性
属性、联合类型、readonly。
PHP 8 新特性
这一课你将能做到
- 用枚举(enum)替代魔法字符串/类常量,给状态字段立起类型护栏
- 用只读属性、命名参数、match、nullsafe 运算符写出紧凑且不可变的现代代码
- 说清 Fiber 协程与线程的区别、JIT 与 OPcache 的关系,并能动手开启 JIT
为什么要学
PHP 8.0(2020)、8.1(2021)、8.2(2022)三连击彻底改变了这门语言的气质:构造器属性提升、枚举、纤程、只读类——把 Laravel 9+、Symfony 6+ 的源码风格推向了「像 Java 又比 Java 省事」。面试官问 PHP 现状,考的就是这些特性;读新框架源码,满屏都是 enum、readonly、fn。停留在 PHP 5 时代的认知,等于看不懂现代 PHP。
人话:这一课是「补差价」——把前几课刻意没展开的高级语法一次讲透,让你写的 PHP 从「能跑」升级到「现代」。
先建立图像
老写法 vs 新写法的直观对比:
// 2010 年代的 PHP // PHP 8.2
class Order { class Order {
const STATUS_PENDING = 1; public function __construct(
public function __construct( public readonly int $id,
private int $status = public readonly OrderStatus $status,
self::STATUS_PENDING ) {}
) {}
} }
enum OrderStatus: string {
case Pending = 'pending';
case Paid = 'paid';
}
魔法值从「常量约定」变成「类型约束」:传错状态直接 TypeError,IDE 自动补全所有合法值。
跟着做
步骤 1:枚举——带方法的类型安全常量
<?php
declare(strict_types=1);
enum OrderStatus: string // backed enum:每个 case 绑定一个标量值
{
case Pending = 'pending';
case Paid = 'paid';
case Shipped = 'shipped';
public function canCancel(): bool // 枚举可以有方法
{
return in_array($this, [self::Pending, self::Paid]);
}
public static function fromDb(?string $v): self // 数据库值 → 枚举
{
return self::tryFrom($v ?? '') ?? self::Pending;
}
}
$status = OrderStatus::Paid;
echo $status->value, PHP_EOL; // paid(取出绑定值)
var_dump($status->canCancel()); // bool(true)
var_dump(OrderStatus::tryFrom('x')); // NULL(非法值不炸)
var_dump(OrderStatus::from('x')); // 抛 ValueError
// 枚举是天然的合法值清单
foreach (OrderStatus::cases() as $case) {
echo $case->name, ' => ', $case->value, PHP_EOL;
}
函数签名写 OrderStatus $status 后,魔法字符串 'paid' 从参数层就绝迹了。
步骤 2:只读属性与只读类
<?php
declare(strict_types=1);
// 8.1:属性级 readonly
class Money
{
public function __construct(
public readonly int $amount, // 初始化后不可修改
public readonly string $currency,
) {}
}
$m = new Money(100, 'CNY');
// $m->amount = 200; // Error: cannot modify readonly property
// 8.2:类级 readonly,所有声明属性自动只读
readonly class Point
{
public function __construct(
public float $x = 0.0,
public float $y = 0.0,
) {}
}
$p = new Point(1.5, 2.5);
echo $p->x + $p->y, PHP_EOL; // 4