PHP 8.1 带来了一个有趣的新特性:只读成员变量。
让我们从一个使用实例开始。
class Test
{
public readonly string $prop;
public function setProp(string $prop): void
{
$this->prop = $prop; // legal initialization
}
}
$test = new Test;
$test->setProp('abc');
echo $test->prop; // legal read
$test->prop = 'foo'; // throws exception: Cannot modify readonly property Test::$prop
因此,一旦一个变量被初始化,它就不能被另一个值所覆盖。
范围
令人惊讶的是,即使变量没有被初始化,向$test->prop 赋值也会抛出一个异常。
$test = new Test;
$test->prop = 'foo';
// throws exception too: Cannot initialize readonly property Test::$prop from global scope
即使这样也会抛出一个异常。
class Child extends Test
{
public function __construct()
{
$this->prop = 'hello';
// throws exception: Cannot initialize readonly property Test::$prop from scope Child
}
}
你根本不能从定义它的类之外的任何地方写到一个只读变量。很奇怪。
不变性
你不能改变只读变量的内容,并不意味着写在那里的数据是不可改变的。如果我们把一个对象写进这样一个变量,我们仍然可以改变它的内部变量。该对象不会成为不可改变的。
对于数组来说也是如此。虽然那里的行为略有不同。改变数组中的元素被认为是改变整个数组,因此在只读变量中是不允许的。但是如果数组中包含一个元素是一个引用,改变它的内容不被认为是对整个数组的改变,因此可以发生在只读元素上。然而,这一直是标准的PHP行为。
换句话说,这是有可能的。
class Test
{
public readonly array $prop;
public function test(): void
{
$item = 'foo';
$this->prop = [1, &$item, 2];
dump($this->prop); // [1, 'foo', 2]
$item = 'bar'; // legal
dump($this->prop); // [1, 'bar', 2]
}
}
但这不能。
class Test
{
public readonly array $prop;
public function test(): void
{
$this->prop = ['a', 'b'];
$this->prop[1] = 'c'; // throws exception!
}
}
类型
因为只读变量利用了有定义类型的变量所存在的 "未初始化 "状态,所以只读变量只能和数据类型一起被指定。