为什么 PHP 在 unset() 声明类型 属性 之后调用 __set()?

Why does PHP call __set() after unset()ing declared typed property?

(编辑了这个问题,旧版本引用了错误版本的RFC。)

RFC for typed properties in PHP says that "If a typed property is unset(), then it returns to the uninitialized state." However, in PHP 7.4 (at least up to 7.4.5), it does appear to behave differently when the class implements __set(), and thus it's not exactly like the (original) uninitialized state. The magic function is not called when the uninitialized property is set for the first time, but it is (unexpectedly) called when the property is set again after having been unset. Example code.

<?php

class X {
    public int $y;
    public function __set($name, $value) {
        echo "__set($name, $value) called";
        $this->$name = $value;
    }
}

$x = new X();
$x->y = 42; // Prints nothing, as expected.
unset($x->y);
$x->y = 43; // Prints `__set(y, 43) called`.

我是不是忽略了什么?这是 PHP 当前如何为类型化属性实现 unset() 的错误吗?或者 __set() 是否应该在第一次设置未初始化类型 属性 时被调用?

魔法getters/setters 只触发不存在的属性。引用:https://www.php.net/manual/en/language.oop5.overloading.php#object.set -> __set() is run when writing data to inaccessible (protected or private) or non-existing properties.

因此在您的示例中,起初 public 变量确实存在。取消设置后,public 变量不会 exist/unintialized 和魔术 getter/setter 到位。

我认为这种行为仍然是错误的,因为 属性 存在但未初始化。应该是错误报告?

为什么?

为了惰性初始化模式的目的。

If a typed property is unset(), then it returns to the uninitialized state. While we would love to remove support for the unsetting of properties, this functionality is currently used for lazy initialization by Doctrine

因此在 PHP 8 中,在提供了一些用于惰性初始化的替代机制之后,他们可能会禁止取消设置已声明的属性。