diff options
Diffstat (limited to 'php/ext/google/protobuf/message.c')
-rw-r--r-- | php/ext/google/protobuf/message.c | 188 |
1 files changed, 150 insertions, 38 deletions
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index 24472682..e28e42a1 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -222,7 +222,13 @@ static zval* message_get_property_ptr_ptr(zval* object, zval* member, int type, } static HashTable* message_get_properties(zval* object TSRMLS_DC) { - return NULL; + // User cannot get property directly (e.g., $a = $m->a) + zend_error(E_USER_ERROR, "Cannot access private properties."); +#if PHP_MAJOR_VERSION < 7 + return zend_std_get_properties(object TSRMLS_CC); +#else + return zend_std_get_properties(object); +#endif } static HashTable* message_get_gc(zval* object, CACHED_VALUE** table, @@ -276,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 = NULL; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + "|a!", &array_wrapper) == FAILURE) { + return; } + + Message_construct(getThis(), array_wrapper); } PHP_METHOD(Message, clear) { @@ -292,7 +401,9 @@ PHP_METHOD(Message, clear) { Descriptor* desc = msg->descriptor; zend_class_entry* ce = desc->klass; + zend_object_std_dtor(&msg->std TSRMLS_CC); object_properties_init(&msg->std, ce); + layout_init(desc->layout, message_data(msg), &msg->std TSRMLS_CC); } @@ -445,8 +556,7 @@ static void init_file_wrappers(TSRMLS_D); // Define file init functions static void init_file_any(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_any) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0acd010a19676f6f676c652f70726f746f6275662f616e792e70726f746f" @@ -461,12 +571,11 @@ static void init_file_any(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_any = true; } static void init_file_api(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_api) return; init_file_source_context(TSRMLS_C); init_file_type(TSRMLS_C); init_generated_pool_once(TSRMLS_C); @@ -502,12 +611,11 @@ static void init_file_api(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_api = true; } static void init_file_duration(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_duration) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0ae3010a1e676f6f676c652f70726f746f6275662f6475726174696f6e2e" @@ -523,12 +631,11 @@ static void init_file_duration(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_duration = true; } static void init_file_field_mask(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_field_mask) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0ae3010a20676f6f676c652f70726f746f6275662f6669656c645f6d6173" @@ -544,12 +651,11 @@ static void init_file_field_mask(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_field_mask = true; } static void init_file_empty(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_empty) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0ab7010a1b676f6f676c652f70726f746f6275662f656d7074792e70726f" @@ -564,12 +670,11 @@ static void init_file_empty(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_empty = true; } static void init_file_source_context(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_source_context) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0afb010a24676f6f676c652f70726f746f6275662f736f757263655f636f" @@ -586,12 +691,11 @@ static void init_file_source_context(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_source_context = true; } static void init_file_struct(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_struct) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0a81050a1c676f6f676c652f70726f746f6275662f7374727563742e7072" @@ -621,12 +725,11 @@ static void init_file_struct(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_struct = true; } static void init_file_timestamp(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_timestamp) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0ae7010a1f676f6f676c652f70726f746f6275662f74696d657374616d70" @@ -642,12 +745,11 @@ static void init_file_timestamp(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_timestamp = true; } static void init_file_type(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_type) return; init_file_any(TSRMLS_C); init_file_source_context(TSRMLS_C); init_generated_pool_once(TSRMLS_C); @@ -711,12 +813,11 @@ static void init_file_type(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_type = true; } static void init_file_wrappers(TSRMLS_D) { - static bool is_initialized = false; - if (is_initialized) return; + if (is_inited_file_wrappers) return; init_generated_pool_once(TSRMLS_C); const char* generated_file = "0abf030a1e676f6f676c652f70726f746f6275662f77726170706572732e" @@ -739,7 +840,7 @@ static void init_file_wrappers(TSRMLS_D) { hex_to_binary(generated_file, &binary, &binary_len); internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); FREE(binary); - is_initialized = true; + is_inited_file_wrappers = true; } // ----------------------------------------------------------------------------- @@ -757,7 +858,7 @@ static zend_function_entry field_cardinality_methods[] = { zend_class_entry* field_cardinality_type; // Init class entry. -PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field_Cardinality", +PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Cardinality", Field_Cardinality, field_cardinality) zend_declare_class_constant_long(field_cardinality_type, "CARDINALITY_UNKNOWN", 19, 0 TSRMLS_CC); @@ -767,6 +868,8 @@ PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field_Cardinality", "CARDINALITY_REQUIRED", 20, 2 TSRMLS_CC); zend_declare_class_constant_long(field_cardinality_type, "CARDINALITY_REPEATED", 20, 3 TSRMLS_CC); + const char *alias = "Google\\Protobuf\\Field_Cardinality"; + zend_register_class_alias_ex(alias, strlen(alias), field_cardinality_type TSRMLS_CC); PHP_PROTO_INIT_ENUMCLASS_END // ----------------------------------------------------------------------------- @@ -780,7 +883,7 @@ static zend_function_entry field_kind_methods[] = { zend_class_entry* field_kind_type; // Init class entry. -PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field_Kind", +PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Kind", Field_Kind, field_kind) zend_declare_class_constant_long(field_kind_type, "TYPE_UNKNOWN", 12, 0 TSRMLS_CC); @@ -820,6 +923,8 @@ PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field_Kind", "TYPE_SINT32", 11, 17 TSRMLS_CC); zend_declare_class_constant_long(field_kind_type, "TYPE_SINT64", 11, 18 TSRMLS_CC); + const char *alias = "Google\\Protobuf\\Field_Kind"; + zend_register_class_alias_ex(alias, strlen(alias), field_kind_type TSRMLS_CC); PHP_PROTO_INIT_ENUMCLASS_END // ----------------------------------------------------------------------------- @@ -928,6 +1033,7 @@ PHP_METHOD(Any, unpack) { PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); zval* type_url_php = php_proto_message_read_property( getThis(), &type_url_member PHP_PROTO_TSRMLS_CC); + zval_dtor(&type_url_member); PHP_PROTO_FAKE_SCOPE_END; // Get fully-qualified name from type url. @@ -938,7 +1044,7 @@ PHP_METHOD(Any, unpack) { if (url_prefix_len > type_url_len || strncmp(TYPE_URL_PREFIX, type_url, url_prefix_len) != 0) { zend_throw_exception( - NULL, "Type url needs to be type.googleapis.com/fully-qulified", + NULL, "Type url needs to be type.googleapis.com/fully-qualified", 0 TSRMLS_CC); return; } @@ -963,6 +1069,7 @@ PHP_METHOD(Any, unpack) { PHP_PROTO_FAKE_SCOPE_RESTART(any_type); zval* value = php_proto_message_read_property( getThis(), &value_member PHP_PROTO_TSRMLS_CC); + zval_dtor(&value_member); PHP_PROTO_FAKE_SCOPE_END; merge_from_string(Z_STRVAL_P(value), Z_STRLEN_P(value), desc, msg); @@ -991,6 +1098,8 @@ PHP_METHOD(Any, pack) { PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); message_handlers->write_property(getThis(), &member, &data, NULL PHP_PROTO_TSRMLS_CC); + zval_dtor(&data); + zval_dtor(&member); PHP_PROTO_FAKE_SCOPE_END; // Set type url. @@ -1008,6 +1117,8 @@ PHP_METHOD(Any, pack) { PHP_PROTO_FAKE_SCOPE_RESTART(any_type); message_handlers->write_property(getThis(), &member, &type_url_php, NULL PHP_PROTO_TSRMLS_CC); + zval_dtor(&type_url_php); + zval_dtor(&member); PHP_PROTO_FAKE_SCOPE_END; FREE(type_url); } @@ -1040,6 +1151,7 @@ PHP_METHOD(Any, is) { PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); zval* value = php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC); + zval_dtor(&member); PHP_PROTO_FAKE_SCOPE_END; // Compare two type url. |