Skip to content

Conversation

@JasonTheAdams
Copy link
Contributor

I found a nuanced situation in how the ModelProperty class determines whether a property is set or not. This ends up bumping into how PHP itself determines whether properties exist and are set on its own objects.

Consider this unit test code:

$definition = (new ModelPropertyDefinition())->nullable();
$property = new ModelProperty('name', $definition);

$property->setValue(null);
$this->assertTrue($property->isSet());

We create a property that is nullable, then we explicitly set that value to null. So, is that property set or not?

Option 1: Follow PHP isset()

If we follow PHP isset() rules, then no, it's not, because null is considered a special value in this case that means something is not set — it is a "nothing" value. Consider this:

$obj = new stdClass;
isset($obj->foo); // false

$obj->foo = null;
isset($obj->foo); // still false

So to align with this means that null is considered a special "nothing" value indicating a property is not set.

Option 2: Follow strict assignment

This PR goes this route. In this case, we're functioning more like PHP's property_exists() function. That is, until a value is explicitly set it is false, but once it is defined then it's true, regardless of whether it's false or not.

Now, you'll notice in this PR I'm not using property_exists(), and that's because it always returns true for a property defined as part of a class, even when that property has no initial value. For this reason, I'm using distinct internal flags for tracking whether the value has been set or not.

Other considerations

If you look at the ModelProperty::__construct (not modified in this PR), you'll notice a special ModelProperty::NO_INITIAL_VALUE is used. This was in light of this concept to differentiate between whether the property was given an initial value, versus it was given an initial value that is null.

This also touches on the idea of dirty/clean values and committing/reverting said changes, as you'll see in the PR changes. The two concepts are connected but not quiet the same.

@JasonTheAdams JasonTheAdams self-assigned this Oct 1, 2025
@JasonTheAdams JasonTheAdams added this to the 2.0 milestone Oct 1, 2025
Copy link
Member

@dpanta94 dpanta94 left a comment

Choose a reason for hiding this comment

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

I think that approach makes more sense when we are talking about a Model. My expectations would be the isset to return true even for null values.

Copy link
Member

@borkweb borkweb left a comment

Choose a reason for hiding this comment

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

Yup - I like this approach.

@JasonTheAdams
Copy link
Contributor Author

Thanks for the confirmation, friends! 🎉

@JasonTheAdams JasonTheAdams merged commit 1dc5cef into release/2.0.0 Oct 1, 2025
2 checks passed
@JasonTheAdams JasonTheAdams deleted the fix/property-set-checking branch October 1, 2025 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants