PHP readonly 属性
最后修改于 2025 年 4 月 16 日
PHP readonly
关键字创建不可变类属性,这些属性只能初始化一次。在 PHP 8.1 中引入,只读属性有助于在面向对象的代码中强制实现不可变性。它们可以防止在初始化后进行修改,使对象更具可预测性。
基本定义
一个 readonly
属性只能在对象初始化期间设置一次。初始化后,该属性不能被修改。只读属性必须具有类型声明。它们可以在构造函数中或直接初始化。
只读属性在初始化后不能被取消设置。它们提供了一种创建不可变对象的简单方法。这对于值对象和 DTO(数据传输对象)很有用,在这些情况下,属性不应该在创建后更改。
语法:readonly type $propertyName
。只读修饰符位于类型声明之前。属性可以是 public、protected 或 private。
基本只读属性
此示例演示了类中的一个简单只读属性。
<?php declare(strict_types=1); class User { public readonly string $name; public function __construct(string $name) { $this->name = $name; } } $user = new User('John'); echo $user->name; // Outputs: John
$name
属性被标记为只读,并在构造函数中初始化。一旦设置,它就不能被更改。尝试稍后修改它会导致错误。这确保了名称在对象创建后保持不变。
具有默认值的只读属性
此示例显示了使用默认值初始化的只读属性。
<?php declare(strict_types=1); class Config { public readonly string $environment = 'production'; } $config = new Config(); echo $config->environment; // Outputs: production
$environment
属性使用默认值进行初始化。由于它是只读的,因此此值以后不能更改。默认值必须是编译时常量。这种模式对于配置值很有用。
在提升构造函数中的只读属性
此示例演示了将 readonly 与构造函数属性提升一起使用。
<?php declare(strict_types=1); class Product { public function __construct( public readonly string $name, public readonly float $price ) {} } $product = new Product('Laptop', 999.99); echo "{$product->name}: {$product->price}"; // Outputs: Laptop: 999.99
构造函数参数被提升为只读属性。这种简洁的语法结合了属性声明和初始化。属性在构造后保持不变。这是值对象的一种常见模式。
尝试修改只读属性
此示例显示了尝试修改只读属性时会发生什么情况。
<?php declare(strict_types=1); class Account { public readonly int $id; public function __construct(int $id) { $this->id = $id; } } $account = new Account(123); // $account->id = 456; // Fatal error: Cannot modify readonly property
代码创建一个具有只读 $id
的 Account。如果取消注释,注释行将导致致命错误。这演示了只读强制的不可变性。当尝试修改时,错误发生在运行时。
所有属性都为只读的只读类
此示例显示了一个类,其中所有属性都被标记为只读。
<?php declare(strict_types=1); readonly class Point { public function __construct( public float $x, public float $y, public float $z ) {} } $point = new Point(1.0, 2.0, 3.0); echo "Point coordinates: {$point->x}, {$point->y}, {$point->z}";
整个 Point
类被标记为只读,默认情况下使所有属性不可变。这从 PHP 8.2 开始可用。这是一种创建不可变值对象的简洁方法。所有属性都必须是类型化和只读的。
具有联合类型的只读属性
此示例演示了将 readonly 与联合类型属性一起使用。
<?php declare(strict_types=1); class Document { public readonly string|int $id; public function __construct(string|int $id) { $this->id = $id; } } $doc1 = new Document('ABC123'); $doc2 = new Document(456); echo "Document IDs: {$doc1->id}, {$doc2->id}";
$id
属性接受字符串或整数值。只读修饰符与联合类型一起使用。一旦初始化,无论其类型如何,该属性都不能被更改。这提供了灵活性,同时保持了不可变性。
继承中的只读属性
此示例显示了只读属性在继承场景中的行为方式。
<?php declare(strict_types=1); class Base { public readonly string $baseProp; public function __construct() { $this->baseProp = 'base'; } } class Child extends Base { public readonly string $childProp; public function __construct() { parent::__construct(); $this->childProp = 'child'; } } $obj = new Child(); echo "{$obj->baseProp}, {$obj->childProp}"; // Outputs: base, child
父类和子类都可以具有只读属性。子类必须初始化其自己的只读属性。父属性通过父构造函数初始化。只读属性通过继承层次结构保持其不可变性。
最佳实践
- 不可变性: 将 readonly 用于不应在创建后更改的属性。
- 值对象: 适用于 DTO、值对象和配置。
- 类型安全: 始终使用只读属性声明类型。
- 初始化: 确保初始化所有只读属性。
- 性能: 只读属性具有最小的运行时开销。
来源
本教程通过实际示例介绍了 PHP 只读属性,展示了它们在各种场景中的用法,以创建不可变对象。
作者
列出 所有 PHP 教程。