Skip to content

modify readonly class property with reference #10844

Closed

Description

@varrg

Description

The following code:

<?php
readonly class A implements IteratorAggregate {
	function __construct(readonly public string $foo = 'bar') {}
	
	function getIterator() : Traversable {
		return new ArrayIterator($this);
	}
}

$obj = new A;
//$obj->foo = 'baz';  // expected fatal error
//$prop = &$obj->foo;  // expected fatal error
foreach ($obj as $k => &$v) {
	$v = 'baz';
}

var_dump($obj);

Resulted in this output:

object(A)#1 (1) {
  ["foo"]=>
  &string(3) "baz"
}

But I expected this output instead:

Fatal error: Uncaught Error: Cannot modify readonly property A::$foo

PHP Version

8.2.3

Operating System

No response

Activity

  1. ndossche commented on Mar 13, 2023

    @ndossche
    Member

    Looks very related to #9432

  2. self-assigned this
    on Mar 17, 2023
  3. iluuu1994 commented on Mar 17, 2023

    @iluuu1994
    Member

    Also related, it's possible to skip the reference type check:

    class A implements IteratorAggregate {
        function __construct(
            public string $foo = 'bar'
        ) {}
    
        function getIterator(): Traversable {
            return new ArrayIterator($this);
        }
    }
    
    $obj = new A;
    foreach ($obj as $k => &$v) {
        $v = 42;
    }
    
    var_dump($obj);
    // object(A)#1 (1) {
    //   ["foo"]=>
    //   &int(42)
    // }
  4. iluuu1994 commented on Mar 17, 2023

    @iluuu1994
    Member

    This seems fairly difficult to fix. The problem is that ArrayIterator copies the properties array without knowing whether the operation is R or RW and ZEND_FE_FETCH_RW converts the given value to a reference without knowing that the value came from an object. Thus we can neither trivially check if the property is readonly, nor add the ZEND_REF_ADD_TYPE_SOURCE when the value is converted to a reference.

    We could specifically fix this for ArrayIterator, which I tried here:
    master...iluuu1994:php-src:gh-10844

    It's not pretty but I don't know how else we could solve this without modifying both the iterator API and the internals of spl_object quite heavily.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions