Skip to content

Hooks scoping: accessing the backing value of a property from a method called from a hook on that property must throw an Error, but infinite loop instead. #18818

New issue

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

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

Already on GitHub? Sign in to your account

Closed
BooleanType opened this issue Jun 9, 2025 · 2 comments

Comments

@BooleanType
Copy link

Description

The following code:

<?php
class Person {
    public string $phone {
        set {
        	$this->phone = $this->sanitizePhone($value);
        }
    }
 
    private function sanitizePhone(string $value): string {
    	$this->phone = 15;
        $value = ltrim($value, '+');
        $value = ltrim($value, '1');
 
        if (!preg_match('/\d\d\d\-\d\d\d\-\d\d\d\d/', $value)) {
            throw new \InvalidArgumentException();
        }
        return $value;
    }
}

$p = new Person;
$p->phone = '+1333-555-1234';

Resulted in this output (an infinite loop:):

Fatal error: Uncaught Error: Maximum call stack size of 8339456 bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion? in /var/www/47ff65bc-ae0d-4698-be01-b9ccf6d20740.php:4 Stack trace: #0 /var/www/47ff65bc-ae0d-4698-be01-b9ccf6d20740.php(11): Person->$phone::set(15) #1 /var/www/47ff65bc-ae0d-4698-be01-b9ccf6d20740.php(5): Person->sanitizePhone('15') #2 /var/www/47ff65bc-ae0d-4698-be01-b9ccf6d20740.php(11): Person->$phone::set('15') #3 /var/www/47ff65bc-ae0d-4698-be01-b9ccf6d20740.php(5): Person->sanitizePhone('15') #4 /var/www/47ff65bc-ae0d-4698-be01-b9ccf6d20740.php(11): Person->$phone::set('15') #5 /var/www/47ff65bc-ae0d-4698-be01-b9ccf6d20740.php(5): Person->sanitizePhone('15')...

But I expected triggering an error, as said in documentation, instead:

If a hook calls a method that in turn tries to read or write from the property again, that would normally result in an infinite loop. To prevent that, accessing the backing value of a property from a method called from a hook on that property will throw an Error. That is somewhat different than the existing behavior of __get and __set, where such sub-called methods would bypass the magic methods. However, as valid use cases for such circular logic are difficult to identify and there is added risk of confusion with dynamic properties, we have elected to simply block that access entirely.

PHP Version

PHP 8.4.5

Operating System

No response

@iluuu1994
Copy link
Member

Hi @BooleanType. Check https://wiki.php.net/rfc/hook_improvements, this part of the RFC was revised.

@iluuu1994 iluuu1994 closed this as not planned Won't fix, can't repro, duplicate, stale Jun 9, 2025
@BooleanType
Copy link
Author

Ahh, ok, didn't notice that. Thanks!

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

No branches or pull requests

2 participants