PHP 8.3 引入了许多值得关注的新特性和改进,可以使代码更安全、更简洁、性能更好。下面是一些关键的新特性(以及相关变更):
核心新特性
1. 类型化类常量(Typed Class Constants)
在 PHP 8.3 之前,常量(const
)不能声明类型。8.3 允许在类、接口、trait 和 enum 的常量上指定类型。 (PHP)
class Foo {
public const string VERSION = "1.0";
}
interface I {
const int MAX = 100;
}
- 如果在基类/接口中声明了常量类型,那么子类/实现类在重写常量时也必须保持兼容类型。 (Kinsta®)
- 允许使用联合类型(如 string|int)来声明常量类型。 (Kinsta®)
2. 动态访问类常量/枚举成员(Dynamic Constant Fetch)
在 PHP 8.3,你可以用类似 C::{$name}
的语法动态访问类常量或枚举成员,替代过去经常用的 constant()
函数。 (PHP)
class Foo {
public const BAR = 123;
}
$name = "BAR";
echo Foo::{$name}; // 123
3. 只读属性的深拷贝(Deep Cloning of readonly
Properties)
PHP 从 8.1 开始支持 readonly
属性,从 8.2 开始支持将整个类标记为 readonly
。在 8.3 中,对 readonly
特性做了重要增强:当对含有 readonly
属性的对象进行克隆(clone
)时,可以在 __clone()
魔术方法中重新初始化这些属性。即,readonly
属性在克隆时可被赋值一次,从而支持“深拷贝”场景。 (PHP)
class A {
public string $value;
}
readonly class B {
public function __construct(
public A $a
) {}
public function __clone(): void {
$this->a = clone $this->a;
}
}
$b1 = new B(new A());
$b2 = clone $b1;
$b2->a->value = "changed"; // 合法
此外,匿名类现在也可以被标记为 readonly
。 (PHP)
4. 新函数 json_validate()
为了解决在只想验证 JSON 字符串是否合法时不得不用 json_decode()
带来额外内存开销的问题,PHP 8.3 引入了 json_validate()
。该函数只验证 JSON 的语法是否合法,不生成对象/数组。 (PHP)
if (json_validate($jsonString)) {
// 是合法 JSON
}
你也可以传入深度和 flags 参数。 (PHP)
5. Random 扩展增强(Randomizer 新方法)
PHP 的 Random 扩展在此前版本就已经引入,8.3 在其基础上做了增强:加入了一些新的方法:
- getBytesFromString(string $str, int $length):从给定字符串随机选取字节生成指定长度的字符串。 (PHP)
- getFloat() / nextFloat():生成浮点数随机值。你可以指定区间以及区间开闭边界。 (Kinsta®)
6. #[\Override]
特性(Attribute)
PHP 8.3 新增了 #[\Override]
属性,用于标注一个方法是对父类或接口方法的覆盖/重写。编译器/检查器可以据此帮助捕获因方法名拼写错误而没有真正覆盖的情况。 (PHP)
class Base {
public function foo() {}
}
class Child extends Base {
#[\Override]
public function foo() {}
}
如果你写错成 fao()
,而标记了 #[\Override]
,就能在静态检查或运行时报错。 (Kinsta®)
7. 其他语法 / 函数 /行为变更与增强
PHP 的官方迁移说明里列出了一些次要但实用的更新: (PHP)
项目 | 描述 |
---|---|
静态变量初始化 | 现在静态变量(static $x = … )可以使用任意表达式作为初始值(以前限制更多) |
从魔术方法创建的闭包支持命名参数 | 在 __call() 、__get() 等魔术方法中创建闭包时可以使用命名参数 |
trait 中的方法可以用 final 修饰 | 在 trait 内部的方法如果不希望被子类重写,可以标记为 final |
class_alias() 支持为内部类创建别名 | 你可以给 PHP 内置类起别名,比如 class_alias('DateTime', 'MyDateTime'); |
新函数 stream_context_set_options() | 为 stream contexts 提供更多选项支持 |
增强 mb_str_pad() 函数 | 新增多字节字符串填充支持 |
更细粒度的 DateTime 异常 | 在处理 DateTime / 日期操作时,异常类型更精细,以便更好捕获错误 |
unserialize() 的通知升级 | 以前某些反序列化错误是 E_NOTICE ,8.3 将升级为 E_WARNING |
SQLite3 扩展的变更 & 弃用 | 一些类和常量做了调整与弃用 |
CLI Lint 支持多文件检查 | php -l 可以同时对多个文件进行语法检查 |
INI 环境变量语法添加 “fallback value” 支持 | 在 php.ini 或环境变量中使用 var ?: default 形式作为回退值支持 |
gc_status() 函数增强 | 新增更多属性,显示垃圾回收运行状态等详细信息 |
弃用某些旧特性 | 比如对不带参数调用的 get_class() / get_parent_class() 可能被弃用或行为改变;还包括 assert() 与 assert_options() 的字符串断言形式被弃用等 |
迁移和兼容性注意
虽然这些特性多数向后兼容,但在升级时要注意:
- 有些旧写法或行为可能触发新的错误/警告(尤其是 unserialize()、SQLite3、trait 方法、常量类型不匹配等)。
- 在代码中使用 #[\Override] 会帮助捕捉本来因为拼写错误或方法签名不匹配而未被覆盖的方法。
- 对于 readonly 的深拷贝功能,如果你在 __clone() 逻辑中重写属性,要谨慎处理以维护不变性原则。
- 第三方库、扩展可能尚未完全适配新版本,升级前要做好测试。