Skip to content

PHPC-1000: Allow bsonSerialize to return BSON structure #1449

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

Merged
merged 10 commits into from
Aug 2, 2023

Conversation

alcaeus
Copy link
Member

@alcaeus alcaeus commented Jul 31, 2023

PHPC-1000

This PR allows implementations of MongoDB\BSON\Serializable to return instances of MongoDB\BSON\Document and MongoDB\BSON\PackedArray. This allows for an easier implementation of the Serializable in PHPLIB classes.

The first commit fixes the tentative return type for Serializable::bsonSerialize: while the original type was array|object, the code actually rejected any object that was not an instance of stdClass. I've also tested the impact on this change: on PHP < 8.1 there is no change as tentative return types are only reported in PHP 8.1+. In those versions, users that have a wider return type (e.g. the original array|object type or object in general), will see a deprecation message that the return types should be compatible. There is no hard break until we make the type non-tentative in PHPC 2.0, so I thought I'd preempt this and fix the return type. This then allows us to specify a return type of array|stdClass|Document|PackedArray in the last commit, which once again is consistent with the values the serializer accepts as return value.

alcaeus added 2 commits July 31, 2023 10:35
The previously indicated return type was incorrect, as returning an object other than stdClass would result in an error.
@alcaeus alcaeus requested a review from jmikola July 31, 2023 11:29
@alcaeus alcaeus self-assigned this Jul 31, 2023
PHONGO_ZVAL_CLASS_OR_TYPE_NAME(obj_data));
zval_ptr_dtor(&obj_data);

return;
}

is_array = php_phongo_is_array_or_document(&obj_data) == IS_ARRAY || (Z_TYPE(obj_data) == IS_OBJECT && instanceof_function(Z_OBJCE(obj_data), php_phongo_packedarray_ce));
Copy link
Member

Choose a reason for hiding this comment

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

The doc block for php_phongo_is_array_or_document() states:

Determines whether the argument should be serialized as a BSON array or document.

Would it make more sense to modify that function to return IS_ARRAY for PackedArray?

Prior to this PR I see two usages of the function, one which handles IS_OBJECT and one for IS_ARRAY. You're modifying the IS_OBJECT case in this PR, so that would leave the second usage in php_phongo_bson_append for IS_ARRAY to be updated (PackedArray is currently handled in the IS_OBJECT case of the surrounding switch).

Copy link
Member Author

Choose a reason for hiding this comment

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

I've changed the function to return IS_ARRAY for PackedArray instances and updated the case in php_phongo_bson_append to only handle zvals of type IS_ARRAY if they also fulfil the php_phongo_is_array_or_document check.

@alcaeus alcaeus force-pushed the phpc-1000-serializable-yield-bson branch from 68e12f3 to b4fb869 Compare August 1, 2023 11:28
@@ -141,7 +164,7 @@ static void php_phongo_bson_append_object(bson_t* bson, php_phongo_field_path* f

/* Persistable objects must always be serialized as BSON documents;
* otherwise, infer based on bsonSerialize()'s return value. */
if (instanceof_function(Z_OBJCE_P(object), php_phongo_persistable_ce) || php_phongo_is_array_or_document(&obj_data) == IS_OBJECT) {
if (instanceof_function(Z_OBJCE_P(object), php_phongo_persistable_ce) || php_phongo_is_array_or_document(&obj_data) != IS_ARRAY) {
Copy link
Member

Choose a reason for hiding this comment

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

I think it'd also help for php_phongo_is_array_or_document to assert that only an object or array is passed in. We don't really have to worry about this thanks to the explicit checks on obj_data above, but it'd be good for peace of mind. I'll make a note of this in PHPC-2217 as well.

Copy link
Member

@jmikola jmikola left a comment

Choose a reason for hiding this comment

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

Some small suggestions to clean things up (and some can wait until PHPC-2217).

LGTM.

@alcaeus alcaeus force-pushed the phpc-1000-serializable-yield-bson branch from b4fb869 to 3c01dd2 Compare August 2, 2023 06:51
@alcaeus alcaeus merged commit e1c09b0 into mongodb:master Aug 2, 2023
@alcaeus alcaeus deleted the phpc-1000-serializable-yield-bson branch August 2, 2023 07:36
Copy link
Member

@jmikola jmikola left a comment

Choose a reason for hiding this comment

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

@alcaeus: I think this needs a quick follow-up commit.

BSON_SERIALIZE_FUNC_NAME,
PHONGO_ZVAL_CLASS_OR_TYPE_NAME(obj_data));
if (!phongo_check_bson_serialize_return_type(&obj_data, Z_OBJCE_P(object))) {
// Exception already thrown
Copy link
Member

Choose a reason for hiding this comment

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

@alcaeus: I see this was already merged, but note that phongo_check_bson_serialize_return_type() can technically return false without throwing an exception if the object is neither Serializable nor Persistable. Perhaps impossible in practice, but I wanted to point it out since this seems like undefined behavior.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point - taken care of in #1453

return true;
}

return false;
Copy link
Member

@jmikola jmikola Aug 3, 2023

Choose a reason for hiding this comment

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

Quoting #1449 (comment):

Consider throwing PHONGO_ERROR_UNEXPECTED_VALUE since we shouldn't get here, but if you want to just return true here you can remove the true returns above and use if/else instead.

If we return false, we should absolutely throw to follow conventions. Otherwise, just return true and NOP.

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.

2 participants