PHP 8.1中的只读变量有什么优势?

232 阅读1分钟

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!
	}
}

类型

因为只读变量利用了有定义类型的变量所存在的 "未初始化 "状态,所以只读变量只能和数据类型一起被指定。