|
@@ -282,15 +282,118 @@ void build_class_from_descriptor(
|
|
// PHP Methods
|
|
// 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
|
|
// 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
|
|
// 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.
|
|
// object. Here, we manually modify it to our message in such a case.
|
|
PHP_METHOD(Message, __construct) {
|
|
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) {
|
|
PHP_METHOD(Message, clear) {
|