Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

After unsetting a typed object property it appears not be uninitialised, but undefined and __get is called #9021

Closed
frankvanhest opened this issue Jul 15, 2022 · 3 comments

Comments

@frankvanhest
Copy link

Description

The following code:

<?php

declare(strict_types=1);

final class Foo
{
    private string $string;

    public function __get(string $propertyName): void
    {
        throw new \Exception('Class property which was unset earlier is now passed to __get');
    }

    public function setString(string $string): void
    {
        $this->string = $string;
    }

    public function string(): string
    {
        return $this->string;
    }

    public function unsetString(): void
    {
        unset($this->string);
    }
}

$foo = new Foo();

try {
    echo $foo->string() . PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage() . PHP_EOL;
}

$foo->setString('test');

echo $foo->string() . PHP_EOL;

$foo->unsetString();

try {
    echo $foo->string() . PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage() . PHP_EOL;
}

Resulted in this output:

Typed property Foo::$string must not be accessed before initialization
test
Class property which was unset earlier is now passed to __get

But I expected this output instead:

Typed property Foo::$string must not be accessed before initialization
test
Typed property Foo::$string must not be accessed before initialization

There was an issue of this way back, https://bugs.php.net/bug.php?id=78904 and the changes are still present in de source code

if (UNEXPECTED(Z_PROP_FLAG_P(retval) == IS_PROP_UNINIT)) {
.

Not sure if this is a bug, or my interpretation of the behaviour for unsetting a typed object property is wrong.

Thank you in advance for looking at this

PHP Version

Latest of PHP 7.4, PHP 8.0, PHP 8.1

Operating System

No response

@mvorisek
Copy link
Contributor

mvorisek commented Jul 15, 2022

I belive the current behaviour is correct - DI/proxy magic would not be possible otherwise - and consistent /w untyped properties.

@frankvanhest
Copy link
Author

I thought so to, but in linked bug report there is a reference to #4974. The coded in this closed MR is still in de current codebase. That's why I'm wondering if it is a bug or not. It could also be that I misread the code ;)

@iluuu1994
Copy link
Member

@frankvanhest From the PR you linked:

Magic will not be triggered for uninitialized typed properties, only explicit unset() ones

This seems to fit this description. It wasn't originally planned this way, according to the RFC:

https://wiki.php.net/rfc/typed_properties_v2#overloaded_properties

If a typed property is in uninitialized state, either because it has not yet been initialized, or because it has been explicitly unset(), then reads from this property will invoke the __get() method if it exists, consistently with the behavior of ordinary properties.

But it looks like the behavior lead to confusion and was thus changed.

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

4 participants