PHP 8.0 新特性
PHP 8.0 是 PHP 语言的一次重大更新,引入了大量新特性,包括 JIT 编译器、联合类型、命名参数、match 表达式、属性(Attributes)、构造器属性提升、Nullsafe 运算符等。这些特性显著提升了 PHP 的表达能力和性能。
前置知识
阅读本节前,建议先了解:PHP 7.4 新特性 的基础知识,以及 类型系统
JIT 编译器(Just-In-Time)
JIT 概述
JIT 编译器在运行时将 PHP 字节码编译为机器码,跳过了解释执行的步骤,显著提升 CPU 密集型任务的性能。
ini
; php.ini
opcache.enable=1
opcache.enable_cli=1
opcache.jit=1255
opcache.jit_buffer_size=128MJIT 配置模式
text
JIT 模式由 4 位数字组成:CRTO
C - CPU 特定的优化 (0=禁用, 1=AVX)
R - 寄存器分配 (0=不使用, 1=使用)
T - 触发器 (0=函数调用时, 1=首次执行时, 2=分析后, 4=首次调用时编译整个函数体, 5=脚本加载时)
O - 优化级别 (0=无优化, 1=最小优化, 2=基于类型推断的优化, 3=基于类型推断和调用图的优化, 4=函数内联, 5=优化已编译代码)
常用模式:
1255 - 最优性能(推荐用于生产环境)
1205 - 适合函数调用频繁的场景
tracing - 函数级别的 JIT
function - 脚本级别的 JITJIT 性能测试
php
<?php
declare(strict_types=1);
// 斐波那契数列 - JIT 显著提升的场景
function fibonacci(int $n): int
{
if ($n <= 1) {
return $n;
}
return fibonacci($n - 1) + fibonacci($n - 2);
}
$start = microtime(true);
echo fibonacci(35) . "\n"; // 9227465
$end = microtime(true);
echo "Time: " . ($end - $start) . " seconds\n";
// 无 JIT: ~4-5 秒
// 有 JIT: ~0.3-0.5 秒(10x 提升)命名参数(Named Arguments)
基本语法
php
<?php
declare(strict_types=1);
// 传统位置参数
function createUser(string $name, string $email, string $role = 'user', bool $active = true): array
{
return compact('name', 'email', 'role', 'active');
}
// PHP 8.0+ 命名参数
createUser(
name: 'John',
email: 'john@example.com',
role: 'admin',
);
// 可以跳过可选参数
createUser(
name: 'Jane',
email: 'jane@example.com',
active: false, // 跳过 $role,直接设置 $active
);
// 参数顺序无关
createUser(
role: 'editor',
name: 'Bob',
email: 'bob@example.com',
);与内置函数配合
php
<?php
declare(strict_types=1);
// PHP 7.x - 必须记住参数顺序
array_slice($array, 0, 10, true);
array_fill(0, 5, 'default');
htmlentities($string, ENT_QUOTES, 'UTF-8');
// PHP 8.0+ - 使用命名参数更清晰
array_slice(array: $array, offset: 0, length: 10, preserve_keys: true);
array_fill(start_index: 0, num: 5, value: 'default');
htmlentities(string: $string, flags: ENT_QUOTES, encoding: 'UTF-8');
// 跳过不需要的参数
setcookie(
name: 'session_id',
value: 'abc123',
httponly: true, // 直接设置第 6 个参数
secure: true, // 直接设置第 7 个参数
samesite: 'Strict', // 直接设置第 8 个参数
);参数传播
展开运算符 ... 在 PHP 8.0+ 支持命名参数传播:
php
$params = ['role' => 'admin', 'active' => false];
createUser(name: 'John', email: 'john@example.com', ...$params);联合类型(Union Types)
基本用法
php
<?php
declare(strict_types=1);
// PHP 8.0 联合类型
function processInput(int|string $input): string
{
if (is_int($input)) {
return "Integer: {$input}";
}
return "String: {$input}";
}
echo processInput(42); // "Integer: 42"
echo processInput('hello'); // "String: hello"
// 联合类型支持 null(等同于 ?Type)
function getUserId(int|null $id): ?int
{
return $id;
}
// 更复杂的联合类型
class OrderService
{
public function findByStatus(Status|string|int $status): array
{
// int: 按 ID 查找
// string: 按状态名查找
// Status: 枚举查找
return match (true) {
$status instanceof Status => $this->findByEnum($status),
is_int($status) => $this->findById($status),
is_string($status) => $this->findByStatusName($status),
};
}
}类型限制
php
<?php
declare(strict_types=1);
// ❌ 不允许的联合类型
function invalid1(void|int $x): void {} // void 不能与其他类型联合
function invalid2(bool|true $x): void {} // true 是 bool 的子类型
function invalid3(int|self $x): void {} // self 仅限于对象类型
// ✅ 允许的联合类型
function valid1(int|null $x): void {} // 可以
function valid2(string|array $x): void {} // 可以
function valid3(DateTimeInterface|null $x): void {} // 接口联合Match 表达式
基本用法
php
<?php
declare(strict_types=1);
// PHP 7.x switch
switch ($status) {
case 'active':
$color = 'green';
break;
case 'pending':
$color = 'yellow';
break;
case 'inactive':
$color = 'red';
break;
default:
$color = 'gray';
}
// PHP 8.0+ match 表达式
$color = match ($status) {
'active' => 'green',
'pending' => 'yellow',
'inactive' => 'red',
default => 'gray',
};Match vs Switch
php
<?php
declare(strict_types=1);
// 1. Match 使用严格比较(===)
$result = match ($value) {
0 => 'zero',
'0' => 'string zero', // 与 0 不同
true => 'boolean true',
};
// 2. Match 可以返回值
$statusLabel = match ($statusCode) {
200, 201, 204 => 'Success',
301, 302 => 'Redirect',
400 => 'Bad Request',
404 => 'Not Found',
500 => 'Server Error',
default => 'Unknown',
};
// 3. Match 支持条件表达式
$discount = match (true) {
$totalAmount > 1000 => 0.15,
$totalAmount > 500 => 0.10,
$totalAmount > 100 => 0.05,
default => 0.0,
};
// 4. Match 支持解构
$result = match ($point) {
[0, 0] => 'Origin',
[0, $y] => "On Y axis at {$y}",
[$x, 0] => "On X axis at {$x}",
[$x, $y] => "Point at ({$x}, {$y})",
};
// 5. Match 不会 fall-through(无需 break)
// 6. Match 如果没有匹配且没有 default,会抛出 UnhandledMatchError属性(Attributes)
内置属性
php
<?php
declare(strict_types=1);
use ReturnTypeWillChange;
use JetBrains\PhpStorm\Deprecated;
use SensitiveParameter;
// 参数属性
#[Attribute]
class MyAttribute
{
public function __construct(
public readonly string $value,
public readonly int $priority = 0,
) {}
}
// 使用属性
#[MyAttribute(value: 'important', priority: 10)]
class UserController
{
#[Route('/api/users', methods: ['GET'])]
#[RateLimit(limit: 100, window: '1 minute')]
public function index(): array
{
return [];
}
#[Route('/api/users/{id}', methods: ['GET'])]
#[Cache(ttl: 300)]
public function show(int $id): array
{
return [];
}
#[Deprecated(reason: 'Use findUser() instead', replacement: 'findUser()')]
public function getUser(int $id): ?User
{
return $this->findUser($id);
}
#[ReturnTypeWillChange]
public function jsonSerialize(): array
{
return [];
}
}自定义属性
php
<?php
declare(strict_types=1);
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Cache
{
public function __construct(
public readonly int $ttl = 3600,
public readonly ?string $key = null,
public readonly array $tags = [],
) {}
}
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class RateLimit
{
public function __construct(
public readonly int $limit = 60,
public readonly string $window = '1 minute',
) {}
}
// 读取属性
$reflectionMethod = new ReflectionMethod(UserController::class, 'index');
$attributes = $reflectionMethod->getAttributes();
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
// $instance 是 Cache 或 RateLimit 对象
if ($instance instanceof Cache) {
echo "Cache TTL: {$instance->ttl}";
}
}构造器属性提升(Constructor Property Promotion)
php
<?php
declare(strict_types=1);
// PHP 7.x 写法
class UserOld
{
private string $name;
private string $email;
private int $age;
public function __construct(string $name, string $email, int $age)
{
$this->name = $name;
$this->email = $email;
$this->age = $age;
}
}
// PHP 8.0+ 构造器属性提升
class User
{
public function __construct(
private readonly string $name,
private readonly string $email,
private readonly int $age,
private readonly ?string $phone = null,
) {}
public function getName(): string
{
return $this->name;
}
public function getEmail(): string
{
return $this->email;
}
}
// 支持的类型修饰符
class Order
{
public function __construct(
public readonly int $id, // public + readonly
private string $status, // private
protected float $amount, // protected
private array $items = [], // 默认值
) {}
}Nullsafe 运算符
php
<?php
declare(strict_types=1);
// PHP 7.x - 多层 null 检查
$country = null;
if ($session !== null) {
$user = $session->getUser();
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->getCountry();
}
}
}
// PHP 8.0+ Nullsafe 运算符
$country = $session?->getUser()?->getAddress()?->getCountry();
// 方法链调用
$result = $repository?->findBy(['status' => 'active'])?->first()?->getName();
// Nullsafe 不影响直接赋值
$name = $user?->getName(); // 如果 $user 为 null,$name = null
// ❌ 不能用于写入
$user?->name = 'John'; // 语法错误字符串相关新函数
php
<?php
declare(strict_types=1);
// str_contains - 检查字符串是否包含子串
str_contains('Hello World', 'World'); // true
str_contains('Hello World', 'world'); // false (大小写敏感)
// str_starts_with - 检查是否以指定字符串开头
str_starts_with('Hello World', 'Hello'); // true
str_starts_with('Hello World', 'World'); // false
// str_ends_with - 检查是否以指定字符串结尾
str_ends_with('Hello World', 'World'); // true
str_ends_with('Hello World', 'Hello'); // false
// PHP 7.x 替代方案
strpos('Hello World', 'World') !== false; // str_contains
substr('Hello World', 0, 5) === 'Hello'; // str_starts_with
substr('Hello World', -5) === 'World'; // str_ends_withThrow 表达式
php
<?php
declare(strict_types=1);
// PHP 7.x - throw 是语句,只能在独立行使用
function validateAge(int $age): void
{
if ($age < 0 || $age > 150) {
throw new InvalidArgumentException('Invalid age');
}
}
// PHP 8.0+ - throw 是表达式,可以在更多地方使用
// 三元运算符中
$value = $age > 0 ? $age : throw new InvalidArgumentException('Age must be positive');
// Null 合并运算符中
$config = $options['timeout'] ?? throw new RuntimeException('Timeout not configured');
// 箭头函数中
$users = array_filter($input, fn ($user) => $user->isActive()
?: throw new InvalidUserException('Inactive user'),
);
// Match 表达式中
$status = match ($code) {
200 => 'OK',
404 => throw new NotFoundException(),
default => 'Unknown',
};注意事项
向后兼容性
PHP 8.0 包含一些不兼容的变更:
@错误抑制运算符不再静默 fatal errors- 默认错误报告级别改为
E_ALL - 比较运算符对数字与非数字字符串的比较方式有变化
- 移除了多个已废弃的功能
最佳实践
- 使用命名参数:提高代码可读性,特别是在调用内置函数时
- 使用 match 替代 switch:更安全、更简洁
- 使用构造器属性提升:减少样板代码
- 使用 Nullsafe 运算符:简化 null 检查链
- 使用属性替代注解:标准化的元数据方式
- 使用联合类型:更精确的类型声明
下一节
继续学习:PHP 8.1 新特性