PHP 只读类有什么限制

wen PHP项目 2

本文目录导读:

PHP 只读类有什么限制

  1. 属性限制
  2. 继承限制
  3. 特质(Trait)限制
  4. 属性修饰符限制
  5. 动态属性限制
  6. 序列化限制
  7. 克隆限制
  8. 反射限制
  9. 属性初始化限制
  10. 访问级别限制

在 PHP 8.2 中引入了只读类(Readonly Classes),这是一个重要的特性,但它也伴随着一系列严格的限制,以下是完整的限制清单:

属性限制

所有属性必须显式声明类型

readonly class User {
    public $name; // ❌ 致命错误:必须声明类型
    public string $email; // ✅ 正确
}

属性必须是 typed 且不能有默认值

readonly class User {
    public string $name = 'John'; // ❌ 致命错误:不能有默认值
    public string $email; // ✅ 正确
}

禁止使用 static 属性

readonly class User {
    public static string $count = '0'; // ❌ 致命错误:不能有静态属性
}

继承限制

只读类不能被子类继承为普通类

readonly class ParentClass {}
class ChildClass extends ParentClass {} // ❌ 致命错误

非只读类不能继承只读类

class ParentClass {}
readonly class ChildClass extends ParentClass {} // ❌ 致命错误

但只读类可以继承只读类

readonly class ParentClass {}
readonly class ChildClass extends ParentClass {} // ✅ 正确

特质(Trait)限制

只读类不能使用含有非只读属性的 trait

trait HasName {
    public string $name = 'John'; // 有默认值
}
readonly class User {
    use HasName; // ❌ 致命错误
}

只读类可以使用只读属性的 trait

trait HasEmail {
    public string $email; // ✅ 符合只读类要求
}
readonly class User {
    use HasEmail; // ✅ 正确
}

属性修饰符限制

不允许使用 var 关键字

readonly class User {
    var string $name; // ❌ 致命错误
    public string $email; // ✅ 正确
}

不允许使用 static 修饰符

readonly class User {
    public static string $count; // ❌ 致命错误
    public string $email; // ✅ 正确
}

动态属性限制

禁止动态创建属性

readonly class User {
    public string $name;
}
$user = new User();
$user->age = 25; // ❌ 致命错误:不能创建动态属性

序列化限制

不兼容 __wakeup()__unserialize()

readonly class User {
    public string $name;
    public function __wakeup() {} // ❌ 致命错误
    // 或
    public function __unserialize(array $data) {} // ❌ 致命错误
}

__serialize() 仍然可以

readonly class User {
    public string $name;
    public function __serialize() { // ✅ 可以(但有警告)
        return ['name' => $this->name];
    }
}

克隆限制

__clone() 方法不能修改属性

readonly class User {
    public string $name;
    public function __clone() {
        $this->name = 'New Name'; // ❌ 致命错误:不能修改只读属性
    }
}

反射限制

ReflectionClass::newInstanceWithoutConstructor() 会创建未初始化状态

$reflection = new ReflectionClass(User::class);
$user = $reflection->newInstanceWithoutConstructor();
echo $user->name; // ❌ 错误:未初始化的属性

属性初始化限制

只能在构造函数中初始化(仅一次)

readonly class User {
    public string $name;
    public function __construct(string $name) {
        $this->name = $name; // ✅ 首次初始化
        $this->name = 'New'; // ❌ 致命错误:不能再次赋值
    }
}

访问级别限制

不允许使用 protectedprivate 属性

readonly class User {
    protected string $name; // ❌ 致命错误
    private string $email;  // ❌ 致命错误
    public string $phone;   // ✅ 正确,只能是 public
}

只读类的核心设计目的是创建不可变的数据对象,这些限制确保了:

  1. 类型安全 - 所有属性必须显式声明类型
  2. 不可变性 - 属性只能在构造函数中初始化一次
  3. 简化继承 - 防止复杂的继承场景
  4. 序列化安全 - 防止反序列化时修改只读属性

使用只读类时,需要仔细考虑这些限制,确保设计符合实际需求。

抱歉,评论功能暂时关闭!