PHP 8.3 正式发布
PHP 8.3 即将于 2023 年 11 月 23 日正式发布。其中新增和更新的内容包括类常量显式类型、json_validate() 函数、动态获取类常量、#[Override] 属性等等。
类常量显式类型
在 PHP 8.2 中,仍然无法声明常量(const)类型,这可能会导致对所使用的类型的混淆:
interface I {
const TEST = "Test"; // We may naively assume that the TEST constant is always a string
}
class Foo implements I {
const TEST = []; // But it may be an array...
}
class Bar extends Foo {
const TEST = null; // Or null
}下例是类型和常量在 PHP 8.3 中的示例:
interface I {
const string TEST = E::TEST; // I::TEST is a string as well
}
class Foo implements I {
use T;
const string TEST = E::TEST; // Foo::TEST must also be a string
}
class Bar extends Foo {
const string TEST = "Test2"; // Bar::TEST must also be a string, but the value can change
}
// Error example
// Fatal error: Cannot use array as value for class constant
// Foo::PHP of type string
class Buzz implements I {
const string PHP = [];
}json_validate() 函数
要在 PHP 中验证 JSON,你需要配置 JSON_THROW_ON_ERROR 标志, 使用 json_last_error,甚至只需确认json_decode() 调用是否为 null。
json_decode(json: '{"foo": "bar}', flags: JSON_THROW_ON_ERROR);
// JsonException Control character error, possibly incorrectly encoded.从 PHP 8.3 开始,你也可以使用 json_validate 函数验证 JSON:
// Valid
json_validate('{"framework": "Laravel"}'); // true
// Invalid
json_validate('{"framework": "Laravel}'); // false
json_last_error_msg(); // Control character error, possibly incorrectly encoded
json_last_error(); // 3动态类常量获取
在 PHP >= 8.2 中,只有使用 `constant()` 函数才能动态获取类常数值。以下情况将导致语法错误:
class Framework {
const NAME = 'Laravel';
}
$name = 'NAME';
// You could achieve this with the constant() function
constant(Framework::class . '::' . $name); // Laravel
// This following is a syntax error in >=v8.2.0
echo Framework::{$name};
// ParseError syntax error, unexpected token ";", expecting "(".从 PHP 8.3 开始,你现在可以从类中动态访问常量,
class Framework {
const NAME = 'Laravel';
}
$name = 'NAME';
// Syntax error in <= v8.2.0
echo Framework::{$name}; // LaravelINI 文件中环境变量的回退值
我最喜欢在 PHP 8.3中 添加的内容之一是在使用环境变量定义 INI 设置时提供默认值。这将简化 Docker 默认值,而不必在 Dockerfile 中将默认值指定为 ENV 块。我相信有很多用例会因此而简化。
例如,假设您希望将 www FPM 池 配置为 DRUPAL_FPM_PORT ENV 值:
error_log = syslog
daemonize = false
[www]
listen = localhost:${DRUPAL_FPM_PORT}必须定义 DRUPAL_FPM_PORT 并且不可能有默认值!现在,您可以执行以下操作,这对于 bash/shell 脚本来说应该很熟悉:
[www]
listen = localhost:${DRUPAL_FPM_PORT:-9000}想象一下,将 xdebug.ini 文件作为 Dockerfile 的一部分进行开发,并使用合理的默认值,同时允许开发人员覆盖他们认为合适的值。
Randomizer 附加
PHP 8.3 包含 Randomizer 附加, 包括新增了一个 getBytesFromString() 方法,该方法用于从源字符串获取随机字节:
$randomizer = new \Random\Randomizer();
printf(
"%s.example.com",
$randomizer->getBytesFromString('abcdefghijklmnopqrstuvwxyz0123456789', 16)
);
// 3zsw04eiubcf82jd.example.com
// Generate a random code for multi-factor authentication
$randomizer = new \Random\Randomizer(new \Random\Engine\Secure());
echo implode('-', str_split($randomizer->getBytesFromString('0123456789', 20), 5));
// 11551-80418-27047-42075新增 #[\Override] 属性
PHP < 8.3
use PHPUnit\Framework\TestCase;
final class MyTest extends TestCase {
protected $logFile;
protected function setUp(): void {
$this->logFile = fopen('/tmp/logfile', 'w');
}
protected function taerDown(): void {
fclose($this->logFile);
unlink('/tmp/logfile');
}
}
// 日志文件不会被移除,因为方法名打错了(taerDown vs tearDown).PHP 8.3
use PHPUnit\Framework\TestCase;
final class MyTest extends TestCase {
protected $logFile;
protected function setUp(): void {
$this->logFile = fopen('/tmp/logfile', 'w');
}
#[\Override]
protected function taerDown(): void {
fclose($this->logFile);
unlink('/tmp/logfile');
}
}
// 致命错误: MyTest::taerDown() 有用 #[\Override] 属性,但是父类中没有相匹配的方法
通过将 #[\Override] 属性添加到方法中,PHP 将确保在父类或实现的接口中存在具有相同名称的方法。添加该属性可以清楚地表明重写父方法是有意的,并简化了重构,因为将检测到对重写的父方法的删除。
PHP < 8.3
class PHP {
public string $version = '8.2';
}
readonly class Foo {
public function __construct(
public PHP $php
) {}
public function __clone(): void {
$this->php = clone $this->php;
}
}
$instance = new Foo(new PHP());
$cloned = clone $instance;
// Fatal error: Cannot modify readonly property Foo::$phpPHP 8.3
class PHP {
public string $version = '8.2';
}
readonly class Foo {
public function __construct(
public PHP $php
) {}
public function __clone(): void {
$this->php = clone $this->php;
}
}
$instance = new Foo(new PHP());
$cloned = clone $instance;
$cloned->php->version = '8.3';readonly 属性现在可以在 __clone 魔术方法中修改一次,以启用只读属性的深度克隆。
更多新特性、变更及特性弃用请查看:
新特性
- 类常量显式类型
- 新增
json_validate函数 - 动态类常量及枚举成员获取
gc_status()返回额外的 GC 信息- Random 扩展 - 新增
\Random\Randomizer::getBytesFromString方法 - Random 扩展 - 新增
\Random\Randomizer::getFloat()和nextFloat()方法
PHP INI 环境变量语法支持回退值
- PHP CLI Lint (
php -l) 支持一次额 linting 多个文件 class_alias()支持内置 PHP 类创建别名- 新增
stream_context_set_options函数
语法/功能变更
unserialize():E_NOTICE错误升级为E_WARNINGhighlight_file和highlight_string输出 HTML 变更- 细粒化
DateTime异常 - 某些PHP扩展类中的类常量类型声明
- 内置 CLI 服务器
$_SERVER['SERVER_SOFTWARE']值更新
废弃