Skip to content

PHP 8.3 新特性

PHP 8.3 引入了类常量类型声明、动态类常量获取(动态类名访问常量)、json_validate() 函数、#[Override] 属性、深度克隆只读属性等特性。这些改进增强了类型安全性和开发便利性。

前置知识

阅读本节前,建议先了解:PHP 8.2 新特性

类常量类型声明

基本用法

php
<?php
declare(strict_types=1);

// PHP 8.3+ 支持类常量的类型声明

class PaymentGateway
{
    // 类型化的类常量
    public const string MODE_LIVE = 'live';
    public const string MODE_TEST = 'test';
    public const int MAX_RETRY = 3;
    public const float TAX_RATE = 0.13;
    public const bool DEBUG = false;
    public const array SUPPORTED_CURRENCIES = ['USD', 'EUR', 'CNY'];
    public const string API_VERSION = 'v2';

    // 接口常量也可以有类型
    final public const string DEFAULT_ENV = 'production';
}

// 枚举常量也支持类型(之前已支持,现在强化)
enum HttpStatus: int
{
    public const int OK_MIN = 200;
    public const int OK_MAX = 299;
    public const int ERROR_MIN = 400;

    case Ok = 200;
    case NotFound = 404;
    case ServerError = 500;
}

接口与 trait 中的常量类型

php
<?php
declare(strict_types=1);

interface Cacheable
{
    public const string CACHE_PREFIX = 'cache_';
    public const int DEFAULT_TTL = 3600;
}

trait HasVersion
{
    public const string VERSION_FIELD = 'version';
    public const int MAX_VERSIONS = 100;
}

class Document implements Cacheable
{
    use HasVersion;
}

常量类型限制

类常量的类型声明支持:stringintfloatboolarray。不支持 voidnullcallableobject 等类型。

动态类常量获取

php
<?php
declare(strict_types=1);

// PHP 8.3+ 支持通过变量访问类常量

class Config
{
    public const string DB_HOST = 'localhost';
    public const string DB_PORT = '3306';
    public const string DB_NAME = 'myapp';
}

// 通过变量获取常量
$field = 'DB_HOST';
echo Config::{$field};  // "localhost"

// 动态获取
function getConstant(string $class, string $constant): mixed
{
    return $class::{$constant};
}

echo getConstant(Config::class, 'DB_HOST');  // "localhost"
echo getConstant(Config::class, 'DB_PORT');  // "3306"

// 与枚举配合
enum Status: string
{
    case Active = 'active';
    case Inactive = 'inactive';
}

$caseName = 'Active';
$status = Status::{$caseName};  // Status::Active
echo $status->value;            // "active"

json_validate() 函数

php
<?php
declare(strict_types=1);

// PHP 8.3+ json_validate() 验证字符串是否为合法 JSON

// 基本用法
json_validate('{"name":"John"}');             // true
json_validate('{"name": "John"}');            // true
json_validate('invalid json');               // false
json_validate('{"name": }');                 // false(语法错误)
json_validate('');                            // false

// 实际应用
function parseJsonRequest(string $body): array
{
    if (!json_validate($body)) {
        throw new InvalidArgumentException('Invalid JSON format');
    }

    $data = json_decode($body, true);

    if ($data === null) {
        throw new InvalidArgumentException('JSON decode failed');
    }

    return $data;
}

// 深度限制验证(PHP 8.3+)
json_validate('{"deep": ' . str_repeat('[', 512) . '}', depth: 512);

json_validate vs json_decode

json_validate()json_decode() + json_last_error() 更快,因为它只验证不解析。适合在解析前做快速检查。

Override 属性

php
<?php
declare(strict_types=1);

use Override;

// PHP 8.3+ #[Override] 属性
// 当方法声明 override 父类方法时,PHP 会验证父类确实有该方法
// 如果父类没有该方法,会产生编译时错误

abstract class BaseService
{
    abstract public function validate(array $data): bool;
    abstract public function process(array $data): void;
    public function log(string $message): void
    {
        echo "[LOG] {$message}\n";
    }
}

class UserService extends BaseService
{
    #[Override]  // 确保父类有 validate 方法
    public function validate(array $data): bool
    {
        return isset($data['email']);
    }

    #[Override]  // 确保父类有 process 方法
    public function process(array $data): void
    {
        echo "Processing user: {$data['email']}\n";
    }

    #[Override]  // 确保父类有 log 方法
    public function log(string $message): void
    {
        echo "[USER LOG] {$message}\n";
    }

    // ❌ 如果误写方法名,#[Override] 会在编译时报错
    // #[Override]
    // public function proces(array $data): void {}  // Error: No method to override
}

深度克隆只读属性

php
<?php
declare(strict_types=1);

// PHP 8.3+ 允许在 __clone() 中修改 readonly 属性

readonly class Address
{
    public function __construct(
        public string $street,
        public string $city,
        public string $country,
    ) {}
}

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

    // PHP 8.3+ 可以在 __clone 中修改 readonly 属性
    public function __clone()
    {
        $this->address = clone $this->address;
        // 之前不能这样做,因为 address 是 readonly
    }
}

$original = new User(
    name: 'John',
    address: new Address('123 Main St', 'New York', 'US'),
);

$clone = clone $original;
$clone->name = 'Jane';  // ❌ 仍然不能修改(readonly)

其他改进

方法参数的匿名类

php
<?php
declare(strict_types=1);

// PHP 8.3+ 允许创建匿名类实例作为参数

$collection = collect([1, 2, 3])
    ->filter(fn (int $item) => $item > 1)
    ->map(fn (int $item) => $item * 2);

获取类名方法改进

php
<?php
declare(strict_types=1);

// PHP 8.3+ 可以获取匿名类的类名
$class = new class {};
echo $class::class;  // class@anonymous /path/to/file.php:line

// 新增方法
$obj = new stdClass();
$className = $obj::class;  // "stdClass"

最佳实践

  1. 使用类常量类型:为类常量添加类型声明,提升类型安全
  2. 使用 #[Override]:防止方法签名不匹配导致的隐含 Bug
  3. 使用 json_validate():在 json_decode 前做快速验证
  4. 利用动态常量获取:减少反射使用,简化动态访问代码

下一节

继续学习:PHP 8.4 新特性

参考链接