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

Closed as not planned
@BooleanType

Description

@BooleanType

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions