2024年PHP开发者大会日本站
已发布!
PHP 8.1 是 PHP 语言的一个重大更新。
它包含许多新特性,包括枚举、只读属性、一等可调用语法、纤程、交集类型、性能改进等等。

枚举 RFC 文档

PHP < 8.1
class Status
{
const
DRAFT = 'draft';
const
PUBLISHED = 'published';
const
ARCHIVED = 'archived';
}
function
acceptStatus(string $status) {...}
PHP 8.1
enum Status
{
case
Draft;
case
Published;
case
Archived;
}
function
acceptStatus(Status $status) {...}
使用枚举代替一组常量,并获得开箱即用的验证。

只读属性 RFC 文档

PHP < 8.1
class BlogData
{
private
Status $status;

public function
__construct(Status $status)
{
$this->status = $status;
}

public function
getStatus(): Status
{
return
$this->status;
}
}
PHP 8.1
class BlogData
{
public readonly
Status $status;

public function
__construct(Status $status)
{
$this->status = $status;
}
}

只读属性在初始化后(即为其赋值后)不能更改。
它们是模拟值对象和数据传输对象的绝佳方式。

一等可调用语法 RFC 文档

PHP < 8.1
$foo = [$this, 'foo'];

$fn = Closure::fromCallable('strlen');
PHP 8.1
$foo = $this->foo(...);

$fn = strlen(...);

现在可以获取任何函数的引用——这称为一等可调用语法。

初始化器中的新特性 RFC

PHP < 8.1
class Service
{
private
Logger $logger;

public function
__construct(
?
Logger $logger = null,
) {
$this->logger = $logger ?? new NullLogger();
}
}
PHP 8.1
class Service
{
private
Logger $logger;

public function
__construct(
Logger $logger = new NullLogger(),
) {
$this->logger = $logger;
}
}

对象现在可以作为默认参数值、静态变量和全局常量使用,以及在属性参数中使用。

这实际上使得使用**嵌套属性**成为可能。

PHP < 8.1
class User
{
/**
* @Assert\All({
* @Assert\NotNull,
* @Assert\Length(min=5)
* })
*/
public string $name = '';
}
PHP 8.1
class User
{
#[
\Assert\All(
new
\Assert\NotNull,
new
\Assert\Length(min: 5))
]
public
string $name = '';
}

纯交集类型 RFC 文档

PHP < 8.1
function count_and_iterate(Iterator $value) {
if (!(
$value instanceof Countable)) {
throw new
TypeError('value must be Countable');
}

foreach (
$value as $val) {
echo
$val;
}

count($value);
}
PHP 8.1
function count_and_iterate(Iterator&Countable $value) {
foreach (
$value as $val) {
echo
$val;
}

count($value);
}

当一个值需要同时满足多个类型约束时,使用交集类型。

目前无法混合使用交集类型和联合类型,例如 A&B|C

永不返回类型 RFC 文档

PHP < 8.1
function redirect(string $uri) {
header('Location: ' . $uri);
exit();
}

function
redirectToLoginPage() {
redirect('/login');
echo
'Hello'; // <- 死代码
}
PHP 8.1
function redirect(string $uri): never {
header('Location: ' . $uri);
exit();
}

function
redirectToLoginPage(): never {
redirect('/login');
echo
'Hello'; // <- 静态分析检测到死代码
}

用 `never` 类型声明的函数或方法表示它不会返回值,并且会抛出异常或使用 `die()`、`exit()`、`trigger_error()` 或类似的方法结束脚本的执行。

最终类常量 RFC 文档

PHP < 8.1
class Foo
{
public const
XX = "foo";
}

class
Bar extends Foo
{
public const
XX = "bar"; // 无错误
}
PHP 8.1
class Foo
{
final public const
XX = "foo";
}

class
Bar extends Foo
{
public const
XX = "bar"; // 致命错误
}

可以声明最终类常量,这样子类就不能重写它们。

显式八进制数值表示法 RFC 文档

PHP < 8.1
016 === 16; // false,因为`016`是八进制的`14`,容易混淆
016 === 14; // true
PHP 8.1
0o16 === 16; // false — 使用显式表示法不会混淆
0o16 === 14; // true

现在可以使用显式的0o前缀编写八进制数。

纤程 RFC 文档

PHP < 8.1
$httpClient->request('https://example.com/')
->
then(function (Response $response) {
return
$response->getBody()->buffer();
})
->
then(function (string $responseBody) {
print
json_decode($responseBody)['code'];
});
PHP 8.1
$response = $httpClient->request('https://example.com/');
print
json_decode($response->getBody()->buffer())['code'];

纤程是实现轻量级协作并发原语。它们是一种创建代码块的方法,这些代码块可以像生成器一样暂停和恢复,但可以在堆栈中的任何位置进行。纤程本身不会神奇地提供并发性,仍然需要一个事件循环。但是,它们允许阻塞和非阻塞实现共享相同的 API。

纤程允许摆脱以前使用Promise::then()或基于生成器的协程看到的样板代码。库通常会在纤程周围构建更高级的抽象,因此无需直接与它们交互。

对字符串键数组的数组解包支持 RFC 文档

PHP < 8.1
$arrayA = ['a' => 1];
$arrayB = ['b' => 2];

$result = array_merge(['a' => 0], $arrayA, $arrayB);

// ['a' => 1, 'b' => 2]
PHP 8.1
$arrayA = ['a' => 1];
$arrayB = ['b' => 2];

$result = ['a' => 0, ...$arrayA, ...$arrayB];

// ['a' => 1, 'b' => 2]

PHP 之前支持通过扩展运算符在数组内解包,但前提是数组必须具有整数键。现在也可以解包具有字符串键的数组。

性能改进

Symfony 演示应用程序请求时间
25 次连续运行,250 个请求 (秒)
(越少越好)

结果(相对于 PHP 8.0)

  • Symfony 演示应用程序速度提升 23.0%
  • WordPress 速度提升 3.5%

PHP 8.1 中与性能相关的功能

  • ARM64 (AArch64) 的 JIT 后端
  • 继承缓存(避免在每个请求中重新链接类)
  • 快速类名解析(避免小写和哈希查找)
  • timelib 和 ext/date 性能改进
  • SPL 文件系统迭代器改进
  • serialize/unserialize 优化
  • 一些内部函数优化 (get_declared_classes()、explode()、strtr()、strnatcmp()、dechex())
  • JIT 改进和修复

新的类、接口和函数

  • 新的#[ReturnTypeWillChange]属性。
  • 新的fsyncfdatasync函数。
  • 新的array_is_list函数。
  • 新的 Sodium XChaCha20 函数。

弃用和向后兼容性中断

  • 将 null 传递给不可为空的内部函数参数已弃用。
  • PHP 内置类方法中的暂定返回类型
  • Serializable接口已弃用。
  • HTML 实体编码/解码函数处理单引号并默认替换。
  • $GLOBALS变量限制。
  • MySQLi:默认错误模式设置为异常。
  • 隐式不兼容的浮点数到整数转换已弃用。
  • finfo 扩展:file_info资源迁移到现有的 finfo 对象。
  • IMAP:imap 资源迁移到IMAP\Connection类对象。
  • FTP 扩展:连接资源迁移到FTP\Connection类对象。
  • GD 扩展:字体标识符迁移到GdFont类对象。
  • LDAP:资源迁移到LDAP\ConnectionLDAP\ResultLDAP\ResultEntry类对象。
  • PostgreSQL:资源迁移到PgSql\ConnectionPgSql\ResultPgSql\Lob类对象。
  • Pspell:pspell、pspell 配置资源迁移到PSpell\DictionaryPSpell\Config类对象。
To Top