Skip to content
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

#126: Fixes issues reading/writing typed properties which are uninitialised #370

Merged
merged 6 commits into from
Jan 9, 2024

Conversation

carnage
Copy link

@carnage carnage commented Dec 14, 2021

#126 documents an issue with the generated hydrator failing with an error when trying to hydrate an object containing typed properties when a typed property is not present in the data array passed to the hydrator, contains no default value and cannot be null.

The fix is to check that the property isset before attempting to do the null check (hydration) or read from the property (extraction). Extraction behaviour for an unset property is not to include the property in the extracted payload; this is to ensure that the behaviour of chained $hydrator->extract() and $hydrator->hydrate() calls continues to work as expected since keeping the property in the array but leaving it null would cause the hydrate call to attempt to set the property to null, this is undesirable as the property type definition doesn't include null and would cause an error.

Have targetted against 4.1.x as this is a bug introduced by PHP 7.4 and this is the most recent version which supports PHP 7.4

This code could be considered a BC break as an operation which previously resulted in an error will now operate correctly, however there are very few scenarios that I can think of where this would cause someone an issue, since using hydration as a means of data validation would be a pretty suspect use case.

Fixes #126

Copy link
Owner

@Ocramius Ocramius left a comment

Choose a reason for hiding this comment

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

Besides minor cleanup (let's move on from 7.3), LGTM 👍

@Ocramius Ocramius added bug dependencies Pull requests that update a dependency file enhancement labels Dec 14, 2021
@Ocramius Ocramius added this to the 4.3.0 milestone Dec 14, 2021
@Ocramius Ocramius changed the base branch from 4.1.x to 4.3.x December 14, 2021 17:20
@Ocramius Ocramius self-assigned this Dec 14, 2021
@Ocramius
Copy link
Owner

Just CS fixes left 👍

$bodyParts[] = $indent . "\$values['" . $propertyName . "'] = \$object->" . $propertyName . ';';

if ($requiresGuard) {
$bodyParts[] = ' }';
Copy link
Author

Choose a reason for hiding this comment

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

not actually sure what the CS rules wanted me to fix here. Surely it doesn't want to invert the condition to put a continue here and then make the assignment outside of the if?

Copy link
Owner

Choose a reason for hiding this comment

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

Yeah, I think it wants a continue; or such - conditionals inside a foreach are (rightfully) frowned upon by the current CS rules

This is what's left:

Error: Equals sign not aligned correctly; expected 1 space but found 2 spaces
Error: Use early exit to reduce code nesting.

Copy link
Author

Choose a reason for hiding this comment

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

That would be objectively worse code; I've extracted it into a method instead

$bodyParts[] = $indent . "\$values['" . $propertyName . "'] = \$object->" . $propertyName . ';';

if ($requiresGuard) {
$bodyParts[] = ' }';
Copy link
Owner

Choose a reason for hiding this comment

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

Yeah, I think it wants a continue; or such - conditionals inside a foreach are (rightfully) frowned upon by the current CS rules

This is what's left:

Error: Equals sign not aligned correctly; expected 1 space but found 2 spaces
Error: Use early exit to reduce code nesting.

@Ocramius Ocramius removed this from the 4.3.0 milestone Jan 11, 2022
@carnage carnage changed the base branch from 4.3.x to 4.4.x July 21, 2022 11:21
@carnage
Copy link
Author

carnage commented Jul 22, 2022

@Ocramius I've rebased this from the latest branch; hopefully that'll resolve the outstanding test coverage issue it was having can you OK the pipeline run?

@Ocramius Ocramius added this to the 4.4.0 milestone Jul 22, 2022
Copy link
Owner

@Ocramius Ocramius left a comment

Choose a reason for hiding this comment

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

LGTM 🚢

Thanks @carnage

@Ocramius
Copy link
Owner

 Error: ] The minimum required MSI percentage should be 95%, but actual is       
         94.04%. Improve your tests!                                            

Sounds like the newly introduced code has mutations to be handled via new tests 🤔

Also, a phpcbf run is needed

@carnage
Copy link
Author

carnage commented Jul 25, 2022

Not entirely sure how to resolve that tbh; the new code does have test coverage. So it's a bit confusing that it's failing on that metric.

@Ocramius
Copy link
Owner

Looking at test failures, I think it's not verifying the generated code output.

@carnage
Copy link
Author

carnage commented Jul 26, 2022

It isn't verifying the generated code output; it's verifying the functioning of the generated code. Most if not all the escaped mutants are basically coding standards failures. eg it's putting whitespace at the end of a line instead of the start by flipping the order of a concat.

Could add a functional test which runs php cs against the generated code to ensure it matches the standards which would catch the mutants; but I'm not convinced of the value of doing that 🤔

@Ocramius
Copy link
Owner

It's either testing the code until there's nothing left to test, or simplifying the code until there's no other way to wiggle it.

It's very much true that things like alignment could be removed from the code generator, for example.

@Ocramius Ocramius removed this from the 4.4.0 milestone Aug 29, 2022
@Ocramius Ocramius removed their assignment Aug 29, 2022
@carnage carnage changed the base branch from 4.4.x to 4.6.x May 25, 2023 11:03
@carnage
Copy link
Author

carnage commented May 25, 2023

@Ocramius I've improved the fix here thanks to a suggestion from my apprentice.

Basically instead of detecting if a property has a type and changing the generated code to add an additional isset, it replaces the !== null check with isset in all cases. This is faster for typed properties and incurs a slight overhead on non-typed properties where the !== null is slightly faster.

I think this is a reasonable trade off as I'd expect most people to be using typed properties on their data objects that they'll use this on.

To solve the infection PHP issues I replaced the string concatenation in the new/changed code with sprintf infection can't mutate the sprintf version of the code without breaking the tests. Unlike the concat version where it could move whitespace around without a noticeable effect.

@pounard
Copy link
Contributor

pounard commented Sep 12, 2023

Will this change be merged soon ? I'm once again bitten by the unitialized property issue.

@Ocramius Ocramius self-assigned this Jan 9, 2024
@Ocramius Ocramius added this to the 4.6.0 milestone Jan 9, 2024
@Ocramius
Copy link
Owner

Ocramius commented Jan 9, 2024

Was on my plate / in background for far too long: thanks @carnage!

@Ocramius Ocramius merged commit 1679eaa into Ocramius:4.6.x Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug dependencies Pull requests that update a dependency file enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Another one with PHP 7.4
3 participants