Skip to content

Allow writing to readonly properties during cloning #9403

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
wants to merge 1 commit into from

Conversation

nicolas-grekas
Copy link
Contributor

@nicolas-grekas nicolas-grekas commented Aug 22, 2022

Here is my try at fixing cloning + readonly. This patch allows readonly properties to be set or unset once during cloning, ie inside __clone(). This makes it straightforward to clone a property when cloning an object. For withers, some coordination is required between __clone and wither methods. See comments for what I mean.

I would love to see this merged as a bugfix in 8.0 (even-though we discuss improved syntax for withers, which don't need to solve for this PR.)

@bwoebi
Copy link
Member

bwoebi commented Aug 24, 2022

I generally agree that clone should generally reset the immutability of readonly.

While I think it makes sense to add a new syntax akin to $foo = clone $bar { prop1 = $something }; or similar (and should probably also apply to new,) this would need to go through the RFC process and should not be tied directly to this feature.

@cmb69
Copy link
Member

cmb69 commented Aug 24, 2022

I would love to see this merged as a bugfix in 8.0 (even-though we discuss improved syntax for withers.)

I don't think there is a bug. The respective RFC mentions:

The clone-based implementation will result in an error, because the x property on the cloned object is already initialized, and modification is thus rejected. This is by design: The property does indeed get modified post-initialization, and the fact that this is only “temporary” is ultimately irrelevant.

So this was a well-known "limitation" of that RFC.

prop_info = zend_get_property_info_for_slot(new_object, dst);
if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
slot = OBJ_PROP(new_object, prop_info->offset);
Z_PROP_FLAG_P(slot) = IS_PROP_UNINIT;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

php > class Foo { public readonly int $x = 0; }
Fatal error: Readonly property Foo::$x cannot have default value in php shell code on line 1

I think the test failures might be related to the fact php internally expects properties with defined values not to have the type IS_PROP_UNINIT, but I'm not completely certain. UNINIT means the value would be IS_UNDEF. In the failing clone tests, they'd have type int for $this->foo = 0, so it sees the property's type is defined and emits the error.

I also don't remember how to properly solve that or what other edge cases there may be

Copy link
Contributor Author

@nicolas-grekas nicolas-grekas Aug 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for chiming in @TysonAndre.
I've figured our that there is another field in the zval that can be used as a flag for what we need: u1.v.u.extra, which looks unused.
I've updated the PR to used it.
I've also figured out other places where this flag should be checked so that my test case passes.
There's a segfault on tests/classes/clone_003.phpt which I don't understand. Anyone would for me please?

@nicolas-grekas nicolas-grekas force-pushed the readonly-uninit branch 3 times, most recently from 7fdd313 to e523c3d Compare August 27, 2022 17:25
@nicolas-grekas
Copy link
Contributor Author

Closing in favor of #9497, thanks @kocsismate for taking over!

@nicolas-grekas nicolas-grekas deleted the readonly-uninit branch October 7, 2022 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants