Hi,

On 12.04.24 04:55, Juliette Reinders Folmer wrote:
Hi Ilija,

On 12-4-2024 1:00, Ilija Tovilo wrote:
<snip>

Oh, and hang on, they *can* be read from a method in the same class as long as 
that method is called from within the set hook, so now the method will need to 
either do a backtrace or use Reflection to figure out whether it has access to 
the property value.
Right. We use the same mechanism as `__get`/`__set` uses to protect
against recursion. In particular, when entering a magic method for a
particular property, PHP remembers this using a "property guard". It's
really just a marker in the object that sets the magic method type,
along with the property name.

When the same property is accessed again, the magic method or hook is
skipped, and PHP behaves as if the magic method or hook wasn't there
at all. For `__get`, `__set` and hooks of virtual properties, this
means accessing a dynamic property. For backed properties, this means
accessing its backing value.

After discussing it, we've decided to make virtual properties slightly
less surprising by throwing, instead of trying to create a dynamic
property. This would be consistent with how virtual read-, and
write-only properties are handled outside of hooks, when they are
written to or read, respectively.

Forgive me, but I had to chuckle at the mention of virtual properties needing to access a dynamic property in the context of a property guard. My thoughts went straight to the following question "Does this mean that support for dynamic properties could never be removed if this RFC gets voted in ? And if so, can we please get rid of the deprecation notice (and need for the attribute) ?"

But I see you've already answered that question by changing the behaviour to throw now. ;-)

This was something I was confused by as well but wasn't sure at all if this would actually be an issue in a real world. So I tried to come up with a real world example.

If I understand correctly you already changed the behavior to throw now but I still want to share anyway ....

Imaging, as library author, you have a property with hooks that contain a typo and you want to rename it in a BC way. Let's say you want to rename "oldProp" to "newProp" but both should work the same as if it would be the same property.

class Test {
    const PREFIX = 'backed:';

    public string $newProp {
        set => $this->prefixize($value);
        get => $this->getProp();
    }

    public string $oldProp {
        set {
            $this->newProp = $value;
        }
        get => $this->getProp();
    }

    /** Complex value transformer */
    private function prefixize($value) {
        return self::PREFIX . $value;
    }

    /** Complex value reverse transformer */
    private function unprefixize($prefixed) {
        return substr($prefixed, strlen(self::PREFIX));
    }

    private function getProp() {
        return $this->unprefixize($this->newProp);
    }
}

$t = new Test();
$t->newProp = 'foo';
var_dump($t); // object(Test)#1 (1) { ["newProp"]=> string(10) "backed:foo" }
var_dump($t->newProp); // string(3) "foo"
var_dump($t->oldProp); // string(0) ""

$t->oldProp = 'bar';
var_dump($t); // { ["newProp"]=> string(10) "backed:bar" }
var_dump($t->newProp); // string(3) "bar"
var_dump($t->oldProp); // string(0) ""


Kind regards,
Marc

Attachment: OpenPGP_0x3936ABF753BC88CE.asc
Description: OpenPGP public key

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

Reply via email to