From 8b336f8c5a77ca4932b00203e485f9266f6f0c30 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Thu, 3 May 2018 10:29:23 -0700 Subject: Implement array constructor in php c extension. --- php/ext/google/protobuf/message.c | 111 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 4 deletions(-) (limited to 'php/ext') diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index c8f4d62b..5a8734bc 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -282,15 +282,118 @@ void build_class_from_descriptor( // PHP Methods // ----------------------------------------------------------------------------- +void Message_construct(zval* msg, zval* array_wrapper) { + zend_class_entry* ce = Z_OBJCE_P(msg); + MessageHeader* intern = NULL; + if (EXPECTED(class_added(ce))) { + intern = UNBOX(MessageHeader, msg); + custom_data_init(ce, intern PHP_PROTO_TSRMLS_CC); + } + + if (array_wrapper == NULL) { + return; + } + + HashTable* array = Z_ARRVAL_P(array_wrapper); + HashPosition pointer; + zval key; + void* value; + const upb_fielddef* field; + + for (zend_hash_internal_pointer_reset_ex(array, &pointer); + php_proto_zend_hash_get_current_data_ex(array, (void**)&value, + &pointer) == SUCCESS; + zend_hash_move_forward_ex(array, &pointer)) { + zend_hash_get_current_key_zval_ex(array, &key, &pointer); + field = upb_msgdef_ntofz(intern->descriptor->msgdef, Z_STRVAL_P(&key)); + if (field == NULL) { + zend_error(E_USER_ERROR, "Unknown field: %s", Z_STRVAL_P(&key)); + } + if (upb_fielddef_ismap(field)) { + PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg)); + zval* submap = message_get_property_internal(msg, &key TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + HashTable* subtable = HASH_OF( + CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value)); + HashPosition subpointer; + zval subkey; + void* memory; + for (zend_hash_internal_pointer_reset_ex(subtable, &subpointer); + php_proto_zend_hash_get_current_data_ex(subtable, (void**)&memory, + &subpointer) == SUCCESS; + zend_hash_move_forward_ex(subtable, &subpointer)) { + zend_hash_get_current_key_zval_ex(subtable, &subkey, &subpointer); + map_field_handlers->write_dimension( + submap, &subkey, + CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC); + zval_dtor(&subkey); + } + } else if (upb_fielddef_isseq(field)) { + PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg)); + zval* subarray = message_get_property_internal(msg, &key TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + HashTable* subtable = HASH_OF( + CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value)); + HashPosition subpointer; + void* memory; + for (zend_hash_internal_pointer_reset_ex(subtable, &subpointer); + php_proto_zend_hash_get_current_data_ex(subtable, (void**)&memory, + &subpointer) == SUCCESS; + zend_hash_move_forward_ex(subtable, &subpointer)) { + repeated_field_handlers->write_dimension( + subarray, NULL, + CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC); + } + } else if (upb_fielddef_issubmsg(field)) { + const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); + PHP_PROTO_HASHTABLE_VALUE desc_php = get_def_obj(submsgdef); + Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php); + zend_property_info* property_info; + PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg)); +#if PHP_MAJOR_VERSION < 7 + property_info = + zend_get_property_info(Z_OBJCE_P(msg), &key, true TSRMLS_CC); +#else + property_info = + zend_get_property_info(Z_OBJCE_P(msg), Z_STR_P(&key), true); +#endif + PHP_PROTO_FAKE_SCOPE_END; + CACHED_VALUE* cached = OBJ_PROP(Z_OBJ_P(msg), property_info->offset); +#if PHP_MAJOR_VERSION < 7 + SEPARATE_ZVAL_IF_NOT_REF(cached); +#endif + zval* submsg = CACHED_PTR_TO_ZVAL_PTR(cached); + ZVAL_OBJ(submsg, desc->klass->create_object(desc->klass TSRMLS_CC)); + Message_construct(submsg, NULL); + MessageHeader* from = UNBOX(MessageHeader, + CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value)); + MessageHeader* to = UNBOX(MessageHeader, submsg); + if(from->descriptor != to->descriptor) { + zend_error(E_USER_ERROR, "Cannot merge messages with different class."); + return; + } + + layout_merge(from->descriptor->layout, from, to TSRMLS_CC); + } else { + message_set_property_internal(msg, &key, + CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value) TSRMLS_CC); + } + zval_dtor(&key); + } +} + // At the first time the message is created, the class entry hasn't been // modified. As a result, the first created instance will be a normal zend // object. Here, we manually modify it to our message in such a case. PHP_METHOD(Message, __construct) { - zend_class_entry* ce = Z_OBJCE_P(getThis()); - if (EXPECTED(class_added(ce))) { - MessageHeader* intern = UNBOX(MessageHeader, getThis()); - custom_data_init(ce, intern PHP_PROTO_TSRMLS_CC); + // Init message with array + zval* array_wrapper; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!", &array_wrapper, + message_type) == FAILURE) { + return; } + + Message_construct(getThis(), array_wrapper); } PHP_METHOD(Message, clear) { -- cgit v1.2.3