PHP 8.3在2023年11月正式发布了,带来了不少实用的新特性和改进。虽然没有PHP 8.0那么革命性的变化,但很多新特性能让代码更简洁、更安全、更易维护。

这篇文章就来详细介绍PHP 8.3的新特性,配合代码示例,帮你快速上手。不管你是PHP新手还是老开发者,都能从中学到东西。

类型化类常量

第一个重要的新特性是类型化类常量(Typed Class Constants)。

在PHP 8.3之前,类常量不能指定类型,虽然可以用const定义常量,但PHP不会检查常量的类型。这就可能导致一些问题,比如子类覆盖父类常量的时候,类型不一致,导致运行时错误。

PHP 8.3之后,可以给类常量指定类型了:

class Config { const string APPNAME = 'My App'; const int MAXUSERS = 1000; const array ALLOWED_ROLES = ['admin', 'user']; }

这样PHP会在编译时检查常量的类型,如果赋值的类型不对,就会报错。比如你给int类型的常量赋值字符串,PHP会直接报错。

类型化类常量在继承的时候也会检查。如果子类覆盖父类的常量,类型必须一致,否则会报错:

class ParentClass { const int VALUE = 1; }

class ChildClass extends ParentClass { const string VALUE = 'hello'; // 报错,类型不匹配 }

这个特性能让代码更安全,避免因为常量类型不一致导致的bug。建议在定义类常量的时候都加上类型声明。

json_validate函数

第二个新特性是json_validate函数。

在PHP 8.3之前,验证一个字符串是不是合法的JSON,通常的做法是用jsondecode,然后判断是否返回null,再用jsonlast_error检查是否有错误。这种方法不仅麻烦,而且会把整个JSON解析成数组或对象,浪费内存。

PHP 8.3新增了json_validate函数,专门用来验证JSON字符串是否合法,不解析内容,效率更高:

$json = '{"name": "张三", "age": 30}';

if (json_validate($json)) { echo "合法的JSON"; } else { echo "不合法的JSON"; }

jsonvalidate只检查语法是否正确,不会把JSON解析成PHP变量,所以比jsondecode快很多,特别是处理大JSON的时候,性能优势明显。

还可以指定深度参数,控制最大嵌套层数:

json_validate($json, 512); // 最大嵌套512层

这个函数虽然简单,但很实用。以后验证JSON就不用再用json_decode那种笨办法了。

深拷贝只读属性

第三个新特性是深拷贝只读属性(Deep Cloning of Readonly Properties)。

PHP 8.1引入了只读属性(readonly),用readonly修饰的属性只能在构造函数里赋值,之后不能修改。这个特性能让不可变对象的实现更简单。

但只读属性有个问题:克隆对象的时候,只读属性不能被修改,所以无法在__clone方法里修改只读属性,这就导致无法实现深拷贝。

PHP 8.3修复了这个问题,现在在__clone方法里可以修改只读属性了:

class User { public function __construct( public readonly string $name, public readonly Address $address, ) {}

public function __clone() { // PHP 8.3之后可以在这里修改只读属性 $this->address = clone $this->address; } }

这样就可以实现深拷贝了,克隆对象的时候,嵌套的对象也会被克隆,而不是共享同一个引用。

这个改进让只读属性更实用了,以前因为无法深拷贝而不敢用readonly的场景,现在可以放心用了。

#[\Override]属性

第四个新特性是#[\Override]属性。

在PHP 8.3之前,如果你想在子类里覆盖父类的方法,直接写一个同名的方法就行。但如果父类的方法名改了或者被删除了,子类的方法就不再是覆盖了,而是一个新方法,PHP不会报错,这可能导致一些难以察觉的bug。

PHP 8.3新增了#[\Override]属性,用这个属性标记的方法,PHP会检查它是否真的覆盖了父类或接口的方法。如果没有覆盖,就会报错:

class ParentClass { public function doSomething() { // ... } }

class ChildClass extends ParentClass { #[\Override] public function doSomething() { // 正确,覆盖了父类方法 }

#[\Override] public function doAnotherThing() { // 报错,父类没有这个方法 } }

这个特性能帮你在重构的时候避免错误。比如你修改了父类的方法名,子类里用了#[\Override]的方法就会报错,提醒你更新子类。如果没有这个属性,子类的方法就变成了一个新方法,可能导致逻辑错误。

建议在覆盖父类方法的时候,都加上#[\Override]属性,这是一个很好的编程习惯。

新的Randomizer方法

第五个新特性是Randomizer类新增了几个方法。

PHP 8.2引入了Randomizer类,提供了更安全、更灵活的随机数生成。PHP 8.3又给Randomizer加了几个实用的方法。

第一个是getBytesFromString,从指定的字符串中随机生成指定长度的字节:

$randomizer = new Random\Randomizer();

// 从指定字符中生成16位随机字符串 $password = $randomizer->getBytesFromString('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 16);

echo $password; // 类似 "aB3kLm9PqR2sT8uV"

这个方法很适合用来生成随机密码、验证码、令牌等。

第二个是nextFloat,生成0到1之间的随机浮点数:

$randomizer = new Random\Randomizer(); $value = $randomizer->nextFloat(); // 0.0 到 1.0 之间

第三个是getFloat,生成指定范围内的随机浮点数:

$randomizer = new Random\Randomizer(); $value = $randomizer->getFloat(1.0, 10.0); // 1.0 到 10.0 之间

还可以指定区间的边界处理方式:

use Random\IntervalBoundary;

$value = $randomizer->getFloat(1.0, 10.0, IntervalBoundary::ClosedOpen); // ClosedOpen: 包含1.0,不包含10.0

这些方法让随机数生成更方便、更安全。建议用Randomizer代替传统的rand和mt_rand。

其他改进

除了上面这些主要的新特性,PHP 8.3还有一些小的改进。

第一个是unserialize的错误处理改进。PHP 8.3之后,unserialize在遇到错误的时候会抛出异常,而不是只返回false。可以用E_WARNING来捕获。

第二个是命令行的改进。PHP 8.3的CLI新增了一些选项,比如--pretty-print可以格式化输出opcache的内容,方便调试。

第三个是性能改进。PHP 8.3在一些场景下有性能提升,比如数组操作、字符串处理、函数调用等。虽然提升幅度不大,但聊胜于无。

第四个是废弃了一些旧的特性。比如废弃了通过引用传递的调用时的警告,还有一些旧的函数别名。这些废弃的特性会在未来的版本中移除,建议提前修改代码。

升级建议

如果你在考虑升级到PHP 8.3,这里有一些建议。

第一,先看官方的迁移指南。PHP官方的迁移指南很详细,列出了所有不兼容的变化和新特性。升级之前一定要仔细看一遍,了解有哪些变化会影响你的代码。

第二,在测试环境先升级。不要直接在生产环境升级,先在测试环境跑一遍,看看有没有兼容性问题。特别是用了很多第三方库的项目,要确认所有依赖都支持PHP 8.3。

第三,用静态分析工具检查。可以用PHPStan、Psalm等静态分析工具,扫描代码中可能存在的兼容性问题。这些工具能帮你发现很多潜在的问题。

第四,逐步升级。如果项目很大,可以先升级到PHP 8.2,稳定之后再升级到8.3。不要跨太多版本升级,否则问题太多不好排查。

第五,做好回滚准备。升级之前做好备份,准备好回滚方案。万一升级之后出了问题,能快速回滚到旧版本。

写在最后

PHP 8.3虽然不是一个革命性的版本,但带来的新特性都很实用。类型化类常量、json_validate、深拷贝只读属性、#[\Override]属性、Randomizer新方法,这些都能让代码更简洁、更安全、更易维护。

PHP这几年的发展很稳健,从PHP 7到PHP 8,性能和特性都有了很大的提升。虽然经常被人调侃,但PHP依然是世界上最好的编程语言之一(之一)。

如果你还在用PHP 7或者更早的版本,建议尽快升级到PHP 8.x。新版本不仅性能更好,安全性也更高,还有很多实用的新特性。

希望这篇入门指南能帮你快速了解PHP 8.3的新特性。有什么问题欢迎交流。