[PHP8.x] 我要引入非对称可见性
Swift 允许您为读取和写入设置不同的可见性。
private (set) public var count: Int = 0 // 読み込みはpublic、書き込みはprivate
这就是为什么肆无忌惮的 PHP 也试图将这个特性引入 PHP 的原因。
以下是相关的RFC,不对称可见性这是一个介绍。
不对称可见性
介绍
PHP 长期以来一直有能力控制属性的可见性。
但是 get 和 set 的功能总是相同的。
该 RFC 建议为属性读取和写入操作提供不同的可见性。
具体来说,它主要是从 Swift 中借来的。
提议
提供新的set
语法,用于声明属性写入操作的可见性。
class Foo
{
public private(set) string $bar;
}
此属性$bar
具有公共读取范围,但具有私有写入范围。
protected(set)
也使它成为受保护的范围。
此属性的行为与常规属性完全相同,只是它的可见性有限。
属性集可见性也可以与构造函数参数提升一起使用。
class Foo
{
public function __construct(
public private(set) string $bar,
) {}
}
参考
只能从可写范围获得对具有设置可见性的属性的引用。
换句话说,引用遵循写入可见性,而不是读取可见性。
class Foo
{
public protected(set) int $bar = 0;
public function test() {
// OK 同クラスなのでprivateは見える
$bar = &$this->bar;
$bar++;
}
}
class Baz extends Foo
{
public function stuff() {
// OK 子クラスなのでprotectedは見える
$bar = &$this->bar;
$bar++;
}
}
$foo = new Foo();
// OK
$foo->test();
// これもOK
$baz = new Baz();
$baz->stuff();
// NG privateには外からアクセスできない
$bar = &$foo->bar;
对象属性
如果目标属性是对象,则设置可见性仅适用于对象更改。
它不会影响对象本身。
这也与只读属性的行为相匹配。
class Bar
{
public string $name = 'beep';
}
class Foo
{
public private(set) Bar $bar;
}
$f = new Foo();
// OK これは許される
$f->bar->name = 'boop';
// NG Foo::$barは外から見れない
$f->bar = new Bar();
允许的可见性
如果 get 和 set 具有不同的可见性,则 set 必须具有比 get 更窄的可见性。
也就是说,可以为集合设置的唯一可见性是protected
和private
。
如果get 的可见性是protected
,那么可以为set 设置的唯一可见性是private
。
任何违规都会导致编译错误。
与 __set 的交互
当类中定义了魔术方法__set
并且从非法范围访问它时,将调用__set
。
这是为了在一个类中为其他目的实现__set
时尽可能防止出现意外行为。
对于只读实现也是如此。
所以我们对不对称可见性有相同的行为。
如果读取可见性不匹配,则调用 __set
。
如果写入可见性不匹配,则为错误。
class Foo {
protected private(set) string $prot;
public private(set) string $pub;
public function __set($name, $value) {
var_dump($name, $value);
}
}
$foo = new Foo();
$foo->prot = 'Foo'; // __setが呼ばれる
$foo->pub = 'Foo'; // エラーになる
与只读的关系
public private(set)
可能看起来与 readonly
相同,但实际上有点不同。
readonly
不允许从public
写入,并且只能从private
写入一次。
public private(set)
不允许从 public
写入,并且允许从 private
无限写入。
您不能在单个属性上同时使用 readonly
和不对称可见性。
类型化的属性
非对称可见性仅适用于具有显式类型的属性。
这主要是由于实现复杂性造成的限制。
具有未知值的属性可以是混合类型,所以这应该不是一个实际问题。
反射
向 ReflectionProperty 添加了两个方法:isProtectedSet():bool
和 isPrivateSet():bool
。
意思是不言自明的。
class Test
{
public string $open;
public protected(set) string $restricted;
}
$rClass = new ReflectionClass(Test::class);
$rOpen = $rClass->getProperty('open');
print $rOpen->isProtectedSet() ? 'Yep' : 'Nope'; // Nope
$rRestricted = $rClass->getProperty('open');
print $rRestricted->isProtectedSet() ? 'Yep' : 'Nope'; // Yep
还添加了常量ReflectionProperty::IS_PROTECTED_SET
和ReflectionProperty::IS_PRIVATE_SET
。
这些被视为从ReflectionProperty::getModifiers()
返回的任何其他可见性修饰符。
向后不兼容的更改
没有向后不兼容的更改。
建议的 PHP 版本
PHP8.3?
未来范围
本节具有前瞻性,不包含在本 RFC 中。
替代操作
目前,唯一可以限定范围的操作是写入和读取。
未来可能会增加其他操作,例如以下。
・init
。 __construct
、__clone
、__unserialize
等属性只能从初始化过程中设置。
・once
。只能写一次。 public private(once)
与readonly
完全相同,但public protected(once)
也可由子类写入。
・unset
。允许取消设置属性。
额外的可见性
如果引入了包级可见性等,public package(set)
等将可用。
属性访问器
对于不对称可见性,我们之前有属性访问器被提议作为 RFC
相关的 RFC 是使用 C# 语法作为模型编写的。
另一方面,这个 RFC 借用了 Swift 的语法,与 C# 风格相比,它有两个优点。
• 减少混乱,因为所有可见性都在一个地方。
- 属性访问器 RFC 面临的问题不受影响。
本 RFC 不排除或限制未来引入属性访问器。
参考
想法
虽然 Nikita 曾经打算将其引入 PHP8.1,辞职属性访问器语法替代。
RFC 说它不会被淘汰,但由于功能几乎相同,如果采用此 RFC,那么引入属性访问器就没有什么意义了。
RFC前几天刚提交,所以还不知道会发生什么,但是我个人认为readonly涵盖了大部分内容,包括属性访问器,所以不知道这个RFC有多少需求. 不是。
此外,private public(set)
无法定义。
我不确定您可以编写但无法读取的属性是什么意思。
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308629114.html
- 上一篇 »python 各种加密加密学习
- 下一篇 »javascript之JSON引入