Add any support in php runtime. (#3486)
* Add any support in php runtime. * Remove unused file in config.m4 * Fix comments * Fix error for tsrmls build * Add newly added file to Makefile.am
This commit is contained in:
parent
98a3734b5a
commit
c7457ef65a
@ -600,6 +600,7 @@ php_EXTRA_DIST= \
|
||||
php/ext/google/protobuf/upb.c \
|
||||
php/ext/google/protobuf/protobuf.c \
|
||||
php/src/phpdoc.dist.xml \
|
||||
php/src/Google/Protobuf/Any.php \
|
||||
php/src/Google/Protobuf/Descriptor.php \
|
||||
php/src/Google/Protobuf/DescriptorPool.php \
|
||||
php/src/Google/Protobuf/EnumDescriptor.php \
|
||||
@ -664,6 +665,7 @@ php_EXTRA_DIST= \
|
||||
php/src/Google/Protobuf/Internal/SourceCodeInfo.php \
|
||||
php/src/Google/Protobuf/Internal/UninterpretedOption_NamePart.php \
|
||||
php/src/Google/Protobuf/Internal/UninterpretedOption.php \
|
||||
php/src/GPBMetadata/Google/Protobuf/Any.php \
|
||||
php/src/GPBMetadata/Google/Protobuf/Internal/Descriptor.php \
|
||||
php/tests/array_test.php \
|
||||
php/tests/autoload.php \
|
||||
|
@ -115,33 +115,6 @@ static void append_map_entry_name(char *result, const char *field_name,
|
||||
check_upb_status(&status, msg); \
|
||||
} while (0)
|
||||
|
||||
// Define PHP class
|
||||
#define DEFINE_PROTOBUF_INIT_CLASS(CLASSNAME, CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_INIT_CLASS_END
|
||||
|
||||
#define DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_CREATE_START(NAME, LOWERNAME) \
|
||||
LOWERNAME##_init_c_instance(intern TSRMLS_CC); \
|
||||
PHP_PROTO_OBJECT_CREATE_END(NAME, LOWERNAME)
|
||||
|
||||
#define DEFINE_PROTOBUF_FREE(CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_FREE_START(CAMELNAME, LOWERNAME) \
|
||||
LOWERNAME##_free_c(intern TSRMLS_CC); \
|
||||
PHP_PROTO_OBJECT_FREE_END
|
||||
|
||||
#define DEFINE_PROTOBUF_DTOR(CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_DTOR_START(CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_DTOR_END
|
||||
|
||||
#define DEFINE_CLASS(NAME, LOWERNAME, string_name) \
|
||||
zend_class_entry *LOWERNAME##_type; \
|
||||
zend_object_handlers *LOWERNAME##_handlers; \
|
||||
DEFINE_PROTOBUF_FREE(NAME, LOWERNAME) \
|
||||
DEFINE_PROTOBUF_DTOR(NAME, LOWERNAME) \
|
||||
DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME) \
|
||||
DEFINE_PROTOBUF_INIT_CLASS(string_name, NAME, LOWERNAME)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPBType
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -657,7 +630,7 @@ zend_object *internal_generated_pool_php;
|
||||
#endif
|
||||
InternalDescriptorPool *generated_pool; // The actual generated pool
|
||||
|
||||
static void init_generated_pool_once(TSRMLS_D) {
|
||||
void init_generated_pool_once(TSRMLS_D) {
|
||||
if (generated_pool == NULL) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
MAKE_STD_ZVAL(generated_pool_php);
|
||||
@ -843,18 +816,11 @@ static void convert_to_class_name_inplace(const char *package,
|
||||
memcpy(classname + i, prefix, prefix_len);
|
||||
}
|
||||
|
||||
PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile) {
|
||||
char *data = NULL;
|
||||
PHP_PROTO_SIZE data_len;
|
||||
void internal_add_generated_file(const char *data, PHP_PROTO_SIZE data_len,
|
||||
InternalDescriptorPool *pool TSRMLS_DC) {
|
||||
upb_filedef **files;
|
||||
size_t i;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
InternalDescriptorPool *pool = UNBOX(InternalDescriptorPool, getThis());
|
||||
CHECK_UPB(files = upb_loaddescriptor(data, data_len, &pool, &status),
|
||||
"Parse binary descriptors to internal descriptors failed");
|
||||
|
||||
@ -913,6 +879,8 @@ PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile) {
|
||||
desc->klass = PHP_PROTO_CE_UNREF(pce); \
|
||||
} \
|
||||
add_ce_obj(desc->klass, desc_php); \
|
||||
add_proto_obj(upb_##def_type_lower##_fullname(desc->def_type_lower), \
|
||||
desc_php); \
|
||||
efree(classname); \
|
||||
break; \
|
||||
}
|
||||
@ -939,6 +907,21 @@ PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile) {
|
||||
upb_gfree(files);
|
||||
}
|
||||
|
||||
PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile) {
|
||||
char *data = NULL;
|
||||
PHP_PROTO_SIZE data_len;
|
||||
upb_filedef **files;
|
||||
size_t i;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
InternalDescriptorPool *pool = UNBOX(InternalDescriptorPool, getThis());
|
||||
internal_add_generated_file(data, data_len, pool TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHP_METHOD(DescriptorPool, getDescriptorByClassName) {
|
||||
DescriptorPool *public_pool = UNBOX(DescriptorPool, getThis());
|
||||
InternalDescriptorPool *pool = public_pool->intern;
|
||||
|
@ -1445,9 +1445,9 @@ static const upb_handlers* msgdef_json_serialize_handlers(
|
||||
// PHP encode/decode methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
PHP_METHOD(Message, serializeToString) {
|
||||
void serialize_to_string(zval* val, zval* return_value TSRMLS_DC) {
|
||||
Descriptor* desc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(val)));
|
||||
|
||||
stringsink sink;
|
||||
stringsink_init(&sink);
|
||||
@ -1461,7 +1461,7 @@ PHP_METHOD(Message, serializeToString) {
|
||||
stackenv_init(&se, "Error occurred during encoding: %s");
|
||||
encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
|
||||
|
||||
putmsg(getThis(), desc, upb_pb_encoder_input(encoder), 0 TSRMLS_CC);
|
||||
putmsg(val, desc, upb_pb_encoder_input(encoder), 0 TSRMLS_CC);
|
||||
|
||||
PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
|
||||
|
||||
@ -1470,6 +1470,26 @@ PHP_METHOD(Message, serializeToString) {
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, serializeToString) {
|
||||
serialize_to_string(getThis(), return_value TSRMLS_CC);
|
||||
}
|
||||
|
||||
void merge_from_string(const char* data, int data_len, const Descriptor* desc,
|
||||
MessageHeader* msg) {
|
||||
const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
|
||||
const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
|
||||
stackenv se;
|
||||
upb_sink sink;
|
||||
upb_pbdecoder* decoder;
|
||||
stackenv_init(&se, "Error occurred during parsing: %s");
|
||||
|
||||
upb_sink_reset(&sink, h, msg);
|
||||
decoder = upb_pbdecoder_create(&se.env, method, &sink);
|
||||
upb_bufsrc_putbuf(data, data_len, upb_pbdecoder_input(decoder));
|
||||
|
||||
stackenv_uninit(&se);
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, mergeFromString) {
|
||||
Descriptor* desc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
|
||||
@ -1483,20 +1503,7 @@ PHP_METHOD(Message, mergeFromString) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
|
||||
const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
|
||||
stackenv se;
|
||||
upb_sink sink;
|
||||
upb_pbdecoder* decoder;
|
||||
stackenv_init(&se, "Error occurred during parsing: %s");
|
||||
|
||||
upb_sink_reset(&sink, h, msg);
|
||||
decoder = upb_pbdecoder_create(&se.env, method, &sink);
|
||||
upb_bufsrc_putbuf(data, data_len, upb_pbdecoder_input(decoder));
|
||||
|
||||
stackenv_uninit(&se);
|
||||
}
|
||||
merge_from_string(data, data_len, desc, msg);
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, serializeToJsonString) {
|
||||
|
@ -32,9 +32,11 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "protobuf.h"
|
||||
#include "utf8.h"
|
||||
|
||||
static zend_class_entry* message_type;
|
||||
zend_class_entry* message_type;
|
||||
zend_object_handlers* message_handlers;
|
||||
static const char TYPE_URL_PREFIX[] = "type.googleapis.com/";
|
||||
|
||||
static zend_function_entry message_methods[] = {
|
||||
PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC)
|
||||
@ -342,3 +344,276 @@ PHP_METHOD(Message, whichOneof) {
|
||||
msg->descriptor->layout, message_data(msg), oneof TSRMLS_CC);
|
||||
PHP_PROTO_RETURN_STRING(oneof_case_name, 1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Any
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static zend_function_entry any_methods[] = {
|
||||
PHP_ME(Any, __construct, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Any, getTypeUrl, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Any, setTypeUrl, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Any, getValue, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Any, setValue, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Any, pack, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Any, unpack, NULL, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(Any, is, NULL, ZEND_ACC_PUBLIC)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
zend_class_entry* any_type;
|
||||
|
||||
// Init class entry.
|
||||
PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Any", Any, any)
|
||||
zend_class_implements(any_type TSRMLS_CC, 1, message_type);
|
||||
zend_declare_property_string(any_type, "type_url", strlen("type_url"),
|
||||
"" ,ZEND_ACC_PRIVATE TSRMLS_CC);
|
||||
zend_declare_property_string(any_type, "value", strlen("value"),
|
||||
"" ,ZEND_ACC_PRIVATE TSRMLS_CC);
|
||||
PHP_PROTO_INIT_SUBMSGCLASS_END
|
||||
|
||||
void hex_to_binary(const char* hex, char** binary, int* binary_len) {
|
||||
int i;
|
||||
int hex_len = strlen(hex);
|
||||
*binary_len = hex_len / 2;
|
||||
*binary = ALLOC_N(char, *binary_len);
|
||||
for (i = 0; i < *binary_len; i++) {
|
||||
char value = 0;
|
||||
if (hex[i * 2] >= '0' && hex[i * 2] <= '9') {
|
||||
value += (hex[i * 2] - '0') * 16;
|
||||
} else {
|
||||
value += (hex[i * 2] - 'a' + 10) * 16;
|
||||
}
|
||||
if (hex[i * 2 + 1] >= '0' && hex[i * 2 + 1] <= '9') {
|
||||
value += hex[i * 2 + 1] - '0';
|
||||
} else {
|
||||
value += hex[i * 2 + 1] - 'a' + 10;
|
||||
}
|
||||
(*binary)[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, __construct) {
|
||||
PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(any_type);
|
||||
if (desc_php == NULL) {
|
||||
init_generated_pool_once(TSRMLS_C);
|
||||
const char* generated_file =
|
||||
"0acd010a19676f6f676c652f70726f746f6275662f616e792e70726f746f"
|
||||
"120f676f6f676c652e70726f746f62756622260a03416e7912100a087479"
|
||||
"70655f75726c180120012809120d0a0576616c756518022001280c426f0a"
|
||||
"13636f6d2e676f6f676c652e70726f746f6275664208416e7950726f746f"
|
||||
"50015a256769746875622e636f6d2f676f6c616e672f70726f746f627566"
|
||||
"2f7074797065732f616e79a20203475042aa021e476f6f676c652e50726f"
|
||||
"746f6275662e57656c6c4b6e6f776e5479706573620670726f746f33";
|
||||
char* binary;
|
||||
int binary_len;
|
||||
hex_to_binary(generated_file, &binary, &binary_len);
|
||||
|
||||
internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
|
||||
FREE(binary);
|
||||
}
|
||||
|
||||
MessageHeader* intern = UNBOX(MessageHeader, getThis());
|
||||
custom_data_init(any_type, intern PHP_PROTO_TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, getTypeUrl) {
|
||||
zval member;
|
||||
PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
|
||||
|
||||
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval* value = message_handlers->read_property(getThis(), &member, BP_VAR_R,
|
||||
NULL PHP_PROTO_TSRMLS_CC);
|
||||
#else
|
||||
zval* value = message_handlers->read_property(getThis(), &member, BP_VAR_R,
|
||||
NULL, NULL PHP_PROTO_TSRMLS_CC);
|
||||
#endif
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
PHP_PROTO_RETVAL_ZVAL(value);
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, setTypeUrl) {
|
||||
char *type_url = NULL;
|
||||
PHP_PROTO_SIZE type_url_len;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &type_url,
|
||||
&type_url_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zval member;
|
||||
zval value;
|
||||
PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
|
||||
PHP_PROTO_ZVAL_STRINGL(&value, type_url, type_url_len, 1);
|
||||
|
||||
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
|
||||
message_handlers->write_property(getThis(), &member, &value,
|
||||
NULL PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
PHP_PROTO_RETVAL_ZVAL(getThis());
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, getValue) {
|
||||
zval member;
|
||||
PHP_PROTO_ZVAL_STRING(&member, "value", 1);
|
||||
|
||||
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
|
||||
zval* value =
|
||||
php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
PHP_PROTO_RETVAL_ZVAL(value);
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, setValue) {
|
||||
char *value = NULL;
|
||||
PHP_PROTO_SIZE value_len;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &value,
|
||||
&value_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zval member;
|
||||
zval value_to_set;
|
||||
PHP_PROTO_ZVAL_STRING(&member, "value", 1);
|
||||
PHP_PROTO_ZVAL_STRINGL(&value_to_set, value, value_len, 1);
|
||||
|
||||
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
|
||||
message_handlers->write_property(getThis(), &member, &value_to_set,
|
||||
NULL PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
PHP_PROTO_RETVAL_ZVAL(getThis());
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, unpack) {
|
||||
// Get type url.
|
||||
zval type_url_member;
|
||||
PHP_PROTO_ZVAL_STRING(&type_url_member, "type_url", 1);
|
||||
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
|
||||
zval* type_url_php = php_proto_message_read_property(
|
||||
getThis(), &type_url_member PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
// Get fully-qualified name from type url.
|
||||
size_t url_prefix_len = strlen(TYPE_URL_PREFIX);
|
||||
const char* type_url = Z_STRVAL_P(type_url_php);
|
||||
size_t type_url_len = Z_STRLEN_P(type_url_php);
|
||||
|
||||
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",
|
||||
0 TSRMLS_CC);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* fully_qualified_name = type_url + url_prefix_len;
|
||||
PHP_PROTO_HASHTABLE_VALUE desc_php = get_proto_obj(fully_qualified_name);
|
||||
if (desc_php == NULL) {
|
||||
zend_throw_exception(
|
||||
NULL, "Specified message in any hasn't been added to descriptor pool",
|
||||
0 TSRMLS_CC);
|
||||
return;
|
||||
}
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php);
|
||||
zend_class_entry* klass = desc->klass;
|
||||
ZVAL_OBJ(return_value, klass->create_object(klass TSRMLS_CC));
|
||||
MessageHeader* msg = UNBOX(MessageHeader, return_value);
|
||||
custom_data_init(klass, msg PHP_PROTO_TSRMLS_CC);
|
||||
|
||||
// Get value.
|
||||
zval value_member;
|
||||
PHP_PROTO_ZVAL_STRING(&value_member, "value", 1);
|
||||
PHP_PROTO_FAKE_SCOPE_RESTART(any_type);
|
||||
zval* value = php_proto_message_read_property(
|
||||
getThis(), &value_member PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
merge_from_string(Z_STRVAL_P(value), Z_STRLEN_P(value), desc, msg);
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, pack) {
|
||||
zval* val;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &val) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!instanceof_function(Z_OBJCE_P(val), message_type TSRMLS_CC)) {
|
||||
zend_error(E_USER_ERROR, "Given value is not an instance of Message.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set value by serialized data.
|
||||
zval data;
|
||||
serialize_to_string(val, &data TSRMLS_CC);
|
||||
|
||||
zval member;
|
||||
PHP_PROTO_ZVAL_STRING(&member, "value", 1);
|
||||
|
||||
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
|
||||
message_handlers->write_property(getThis(), &member, &data,
|
||||
NULL PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
// Set type url.
|
||||
Descriptor* desc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(val)));
|
||||
const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef);
|
||||
size_t type_url_len =
|
||||
strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1;
|
||||
char* type_url = ALLOC_N(char, type_url_len);
|
||||
sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name);
|
||||
zval type_url_php;
|
||||
PHP_PROTO_ZVAL_STRING(&type_url_php, type_url, 1);
|
||||
PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
|
||||
|
||||
PHP_PROTO_FAKE_SCOPE_RESTART(any_type);
|
||||
message_handlers->write_property(getThis(), &member, &type_url_php,
|
||||
NULL PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
FREE(type_url);
|
||||
}
|
||||
|
||||
PHP_METHOD(Any, is) {
|
||||
zend_class_entry *klass = NULL;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &klass) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(klass);
|
||||
if (desc_php == NULL) {
|
||||
RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
// Create corresponded type url.
|
||||
Descriptor* desc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(klass));
|
||||
const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef);
|
||||
size_t type_url_len =
|
||||
strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1;
|
||||
char* type_url = ALLOC_N(char, type_url_len);
|
||||
sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name);
|
||||
|
||||
// Fetch stored type url.
|
||||
zval member;
|
||||
PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
|
||||
PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
|
||||
zval* value =
|
||||
php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC);
|
||||
PHP_PROTO_FAKE_SCOPE_END;
|
||||
|
||||
// Compare two type url.
|
||||
bool is = strcmp(type_url, Z_STRVAL_P(value)) == 0;
|
||||
FREE(type_url);
|
||||
|
||||
RETURN_BOOL(is);
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ static HashTable* upb_def_to_php_obj_map;
|
||||
// Global map from message/enum's php class entry to corresponding wrapper
|
||||
// Descriptor/EnumDescriptor instances.
|
||||
static HashTable* ce_to_php_obj_map;
|
||||
// Global map from message/enum's proto fully-qualified name to corresponding
|
||||
// wrapper Descriptor/EnumDescriptor instances.
|
||||
static HashTable* proto_to_php_obj_map;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Global maps.
|
||||
@ -80,6 +83,22 @@ static void add_to_list(HashTable* t, void* value) {
|
||||
(void**)&pDest);
|
||||
}
|
||||
|
||||
static void add_to_strtable(HashTable* t, const char* key, int key_size,
|
||||
void* value) {
|
||||
zval* pDest = NULL;
|
||||
php_proto_zend_hash_update_mem(t, key, key_size, &value, sizeof(void*),
|
||||
(void**)&pDest);
|
||||
}
|
||||
|
||||
static void* get_from_strtable(const HashTable* t, const char* key, int key_size) {
|
||||
void** value;
|
||||
if (php_proto_zend_hash_find_mem(t, key, key_size, (void**)&value) ==
|
||||
FAILURE) {
|
||||
return NULL;
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
void add_def_obj(const void* def, PHP_PROTO_HASHTABLE_VALUE value) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
Z_ADDREF_P(value);
|
||||
@ -110,6 +129,20 @@ bool class_added(const void* ce) {
|
||||
return exist_in_table(ce_to_php_obj_map, ce);
|
||||
}
|
||||
|
||||
void add_proto_obj(const char* proto, PHP_PROTO_HASHTABLE_VALUE value) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
Z_ADDREF_P(value);
|
||||
#else
|
||||
++GC_REFCOUNT(value);
|
||||
#endif
|
||||
add_to_strtable(proto_to_php_obj_map, proto, strlen(proto), value);
|
||||
}
|
||||
|
||||
PHP_PROTO_HASHTABLE_VALUE get_proto_obj(const char* proto) {
|
||||
return (PHP_PROTO_HASHTABLE_VALUE)get_from_strtable(proto_to_php_obj_map,
|
||||
proto, strlen(proto));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utilities.
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -163,6 +196,9 @@ static PHP_RINIT_FUNCTION(protobuf) {
|
||||
ALLOC_HASHTABLE(ce_to_php_obj_map);
|
||||
zend_hash_init(ce_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0);
|
||||
|
||||
ALLOC_HASHTABLE(proto_to_php_obj_map);
|
||||
zend_hash_init(proto_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0);
|
||||
|
||||
generated_pool = NULL;
|
||||
generated_pool_php = NULL;
|
||||
internal_generated_pool_php = NULL;
|
||||
@ -177,6 +213,9 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) {
|
||||
zend_hash_destroy(ce_to_php_obj_map);
|
||||
FREE_HASHTABLE(ce_to_php_obj_map);
|
||||
|
||||
zend_hash_destroy(proto_to_php_obj_map);
|
||||
FREE_HASHTABLE(proto_to_php_obj_map);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
if (generated_pool_php != NULL) {
|
||||
zval_dtor(generated_pool_php);
|
||||
@ -217,6 +256,7 @@ static PHP_MINIT_FUNCTION(protobuf) {
|
||||
repeated_field_init(TSRMLS_C);
|
||||
repeated_field_iter_init(TSRMLS_C);
|
||||
util_init(TSRMLS_C);
|
||||
any_init(TSRMLS_C);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -77,15 +77,28 @@
|
||||
#define php_proto_zend_hash_index_update_zval(ht, h, pData) \
|
||||
zend_hash_index_update(ht, h, &(pData), sizeof(void*), NULL)
|
||||
|
||||
#define php_proto_zend_hash_update_zval(ht, key, key_len, value) \
|
||||
zend_hash_update(ht, key, key_len, value, sizeof(void*), NULL)
|
||||
|
||||
#define php_proto_zend_hash_index_update_mem(ht, h, pData, nDataSize, pDest) \
|
||||
zend_hash_index_update(ht, h, pData, nDataSize, pDest)
|
||||
|
||||
#define php_proto_zend_hash_update_mem(ht, key, key_len, pData, nDataSize, \
|
||||
pDest) \
|
||||
zend_hash_update(ht, key, key_len, pData, nDataSize, pDest)
|
||||
|
||||
#define php_proto_zend_hash_index_find_zval(ht, h, pDest) \
|
||||
zend_hash_index_find(ht, h, pDest)
|
||||
|
||||
#define php_proto_zend_hash_index_find_mem(ht, h, pDest) \
|
||||
zend_hash_index_find(ht, h, pDest)
|
||||
|
||||
#define php_proto_zend_hash_find_zval(ht, key, key_len, pDest) \
|
||||
zend_hash_find(ht, key, key_len, pDest)
|
||||
|
||||
#define php_proto_zend_hash_find_mem(ht, key, key_len, pDest) \
|
||||
zend_hash_find(ht, key, key_len, pDest)
|
||||
|
||||
#define php_proto_zend_hash_next_index_insert_zval(ht, pData) \
|
||||
zend_hash_next_index_insert(ht, pData, sizeof(void*), NULL)
|
||||
|
||||
@ -103,6 +116,17 @@
|
||||
#define PHP_PROTO_WRAP_OBJECT_END \
|
||||
};
|
||||
|
||||
#define PHP_PROTO_INIT_SUBMSGCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \
|
||||
void LOWWERNAME##_init(TSRMLS_D) { \
|
||||
zend_class_entry class_type; \
|
||||
const char* class_name = CLASSNAME; \
|
||||
INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \
|
||||
LOWWERNAME##_methods); \
|
||||
LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
|
||||
LOWWERNAME##_type->create_object = message_create;
|
||||
#define PHP_PROTO_INIT_SUBMSGCLASS_END \
|
||||
}
|
||||
|
||||
#define PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \
|
||||
void LOWWERNAME##_init(TSRMLS_D) { \
|
||||
zend_class_entry class_type; \
|
||||
@ -202,6 +226,8 @@
|
||||
#define php_proto_zend_lookup_class(name, name_length, ce) \
|
||||
zend_lookup_class(name, name_length, ce TSRMLS_CC)
|
||||
|
||||
#define PHP_PROTO_RETVAL_ZVAL(value) ZVAL_ZVAL(return_value, value, 1, 0)
|
||||
|
||||
#else // PHP_MAJOR_VERSION >= 7
|
||||
|
||||
#define php_proto_zend_literal void**
|
||||
@ -243,6 +269,23 @@ static inline int php_proto_zend_hash_index_update_mem(HashTable* ht, ulong h,
|
||||
return result != NULL ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
static inline int php_proto_zend_hash_update_zval(HashTable* ht,
|
||||
const char* key, uint key_len,
|
||||
zval* pData) {
|
||||
zend_string* internal_key = zend_string_init(key, key_len, 0);
|
||||
zend_hash_update(ht, internal_key, pData);
|
||||
}
|
||||
|
||||
static inline int php_proto_zend_hash_update_mem(HashTable* ht, const char* key,
|
||||
uint key_len, void* pData,
|
||||
uint nDataSize, void** pDest) {
|
||||
zend_string* internal_key = zend_string_init(key, key_len, 0);
|
||||
void* result = zend_hash_update_mem(ht, internal_key, pData, nDataSize);
|
||||
zend_string_release(internal_key);
|
||||
if (pDest != NULL) *pDest = result;
|
||||
return result != NULL ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
static inline int php_proto_zend_hash_index_find_zval(const HashTable* ht,
|
||||
ulong h, void** pDest) {
|
||||
zval* result = zend_hash_index_find(ht, h);
|
||||
@ -258,6 +301,25 @@ static inline int php_proto_zend_hash_index_find_mem(const HashTable* ht,
|
||||
return result != NULL ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
static inline int php_proto_zend_hash_find_zval(const HashTable* ht,
|
||||
const char* key, uint key_len,
|
||||
void** pDest) {
|
||||
zend_string* internal_key = zend_string_init(key, key_len, 1);
|
||||
zval* result = zend_hash_find(ht, internal_key);
|
||||
if (pDest != NULL) *pDest = result;
|
||||
return result != NULL ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
static inline int php_proto_zend_hash_find_mem(const HashTable* ht,
|
||||
const char* key, uint key_len,
|
||||
void** pDest) {
|
||||
zend_string* internal_key = zend_string_init(key, key_len, 1);
|
||||
void* result = zend_hash_find_ptr(ht, internal_key);
|
||||
zend_string_release(internal_key);
|
||||
if (pDest != NULL) *pDest = result;
|
||||
return result != NULL ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
static inline int php_proto_zend_hash_next_index_insert_zval(HashTable* ht,
|
||||
void* pData) {
|
||||
zval tmp;
|
||||
@ -292,6 +354,17 @@ static inline int php_proto_zend_hash_get_current_data_ex(HashTable* ht,
|
||||
zend_object std; \
|
||||
};
|
||||
|
||||
#define PHP_PROTO_INIT_SUBMSGCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \
|
||||
void LOWWERNAME##_init(TSRMLS_D) { \
|
||||
zend_class_entry class_type; \
|
||||
const char* class_name = CLASSNAME; \
|
||||
INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \
|
||||
LOWWERNAME##_methods); \
|
||||
LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
|
||||
LOWWERNAME##_type->create_object = message_create;
|
||||
#define PHP_PROTO_INIT_SUBMSGCLASS_END \
|
||||
}
|
||||
|
||||
#define PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \
|
||||
void LOWWERNAME##_init(TSRMLS_D) { \
|
||||
zend_class_entry class_type; \
|
||||
@ -390,12 +463,60 @@ static inline int php_proto_zend_lookup_class(
|
||||
return *ce != NULL ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
#define PHP_PROTO_RETVAL_ZVAL(value) ZVAL_COPY(return_value, value)
|
||||
|
||||
#endif // PHP_MAJOR_VERSION >= 7
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
|
||||
#define PHP_PROTO_FAKE_SCOPE_BEGIN(klass) \
|
||||
zend_class_entry* old_scope = EG(scope); \
|
||||
EG(scope) = klass;
|
||||
#define PHP_PROTO_FAKE_SCOPE_RESTART(klass) \
|
||||
old_scope = EG(scope); \
|
||||
EG(scope) = klass;
|
||||
#define PHP_PROTO_FAKE_SCOPE_END EG(scope) = old_scope;
|
||||
#else
|
||||
#define PHP_PROTO_FAKE_SCOPE_BEGIN(klass) \
|
||||
zend_class_entry* old_scope = EG(fake_scope); \
|
||||
EG(fake_scope) = klass;
|
||||
#define PHP_PROTO_FAKE_SCOPE_RESTART(klass) \
|
||||
old_scope = EG(fake_scope); \
|
||||
EG(fake_scope) = klass;
|
||||
#define PHP_PROTO_FAKE_SCOPE_END EG(fake_scope) = old_scope;
|
||||
#endif
|
||||
|
||||
// Define PHP class
|
||||
#define DEFINE_PROTOBUF_INIT_CLASS(CLASSNAME, CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_INIT_CLASS_END
|
||||
|
||||
#define DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_CREATE_START(NAME, LOWERNAME) \
|
||||
LOWERNAME##_init_c_instance(intern TSRMLS_CC); \
|
||||
PHP_PROTO_OBJECT_CREATE_END(NAME, LOWERNAME)
|
||||
|
||||
#define DEFINE_PROTOBUF_FREE(CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_FREE_START(CAMELNAME, LOWERNAME) \
|
||||
LOWERNAME##_free_c(intern TSRMLS_CC); \
|
||||
PHP_PROTO_OBJECT_FREE_END
|
||||
|
||||
#define DEFINE_PROTOBUF_DTOR(CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_DTOR_START(CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_DTOR_END
|
||||
|
||||
#define DEFINE_CLASS(NAME, LOWERNAME, string_name) \
|
||||
zend_class_entry *LOWERNAME##_type; \
|
||||
zend_object_handlers *LOWERNAME##_handlers; \
|
||||
DEFINE_PROTOBUF_FREE(NAME, LOWERNAME) \
|
||||
DEFINE_PROTOBUF_DTOR(NAME, LOWERNAME) \
|
||||
DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME) \
|
||||
DEFINE_PROTOBUF_INIT_CLASS(string_name, NAME, LOWERNAME)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Forward Declaration
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct Any;
|
||||
struct DescriptorPool;
|
||||
struct Descriptor;
|
||||
struct EnumDescriptor;
|
||||
@ -411,6 +532,7 @@ struct Map;
|
||||
struct MapIter;
|
||||
struct Oneof;
|
||||
|
||||
typedef struct Any Any;
|
||||
typedef struct DescriptorPool DescriptorPool;
|
||||
typedef struct Descriptor Descriptor;
|
||||
typedef struct EnumDescriptor EnumDescriptor;
|
||||
@ -434,6 +556,7 @@ ZEND_BEGIN_MODULE_GLOBALS(protobuf)
|
||||
ZEND_END_MODULE_GLOBALS(protobuf)
|
||||
|
||||
// Init module and PHP classes.
|
||||
void any_init(TSRMLS_D);
|
||||
void descriptor_init(TSRMLS_D);
|
||||
void enum_descriptor_init(TSRMLS_D);
|
||||
void descriptor_pool_init(TSRMLS_D);
|
||||
@ -442,11 +565,11 @@ void field_descriptor_init(TSRMLS_D);
|
||||
void gpb_type_init(TSRMLS_D);
|
||||
void map_field_init(TSRMLS_D);
|
||||
void map_field_iter_init(TSRMLS_D);
|
||||
void message_init(TSRMLS_D);
|
||||
void oneof_descriptor_init(TSRMLS_D);
|
||||
void repeated_field_init(TSRMLS_D);
|
||||
void repeated_field_iter_init(TSRMLS_D);
|
||||
void util_init(TSRMLS_D);
|
||||
void message_init(TSRMLS_D);
|
||||
|
||||
// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
|
||||
// instances.
|
||||
@ -459,6 +582,11 @@ void add_ce_obj(const void* ce, PHP_PROTO_HASHTABLE_VALUE value);
|
||||
PHP_PROTO_HASHTABLE_VALUE get_ce_obj(const void* ce);
|
||||
bool class_added(const void* ce);
|
||||
|
||||
// Global map from message/enum's proto fully-qualified name to corresponding
|
||||
// wrapper Descriptor/EnumDescriptor instances.
|
||||
void add_proto_obj(const char* proto, PHP_PROTO_HASHTABLE_VALUE value);
|
||||
PHP_PROTO_HASHTABLE_VALUE get_proto_obj(const char* proto);
|
||||
|
||||
extern zend_class_entry* map_field_type;
|
||||
extern zend_class_entry* repeated_field_type;
|
||||
|
||||
@ -482,6 +610,10 @@ PHP_PROTO_WRAP_OBJECT_END
|
||||
PHP_METHOD(InternalDescriptorPool, getGeneratedPool);
|
||||
PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile);
|
||||
|
||||
void internal_add_generated_file(const char* data, PHP_PROTO_SIZE data_len,
|
||||
InternalDescriptorPool* pool TSRMLS_DC);
|
||||
void init_generated_pool_once(TSRMLS_D);
|
||||
|
||||
// wrapper of generated pool
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
extern zval* generated_pool_php;
|
||||
@ -567,6 +699,7 @@ void custom_data_init(const zend_class_entry* ce,
|
||||
void build_class_from_descriptor(
|
||||
PHP_PROTO_HASHTABLE_VALUE php_descriptor TSRMLS_DC);
|
||||
|
||||
extern zend_class_entry* message_type;
|
||||
extern zend_object_handlers* message_handlers;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -674,6 +807,9 @@ PHP_METHOD(Message, __construct);
|
||||
// This is called from the message class creation code.
|
||||
const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc,
|
||||
const void *owner);
|
||||
void serialize_to_string(zval* val, zval* return_value TSRMLS_DC);
|
||||
void merge_from_string(const char* data, int data_len, const Descriptor* desc,
|
||||
MessageHeader* msg);
|
||||
|
||||
PHP_METHOD(Message, serializeToString);
|
||||
PHP_METHOD(Message, mergeFromString);
|
||||
@ -880,6 +1016,21 @@ extern zend_class_entry* oneof_descriptor_type;
|
||||
// have a number of 0.
|
||||
#define ONEOF_CASE_NONE 0
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Well Known Type.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
PHP_METHOD(Any, __construct);
|
||||
PHP_METHOD(Any, getTypeUrl);
|
||||
PHP_METHOD(Any, setTypeUrl);
|
||||
PHP_METHOD(Any, getValue);
|
||||
PHP_METHOD(Any, setValue);
|
||||
PHP_METHOD(Any, unpack);
|
||||
PHP_METHOD(Any, pack);
|
||||
PHP_METHOD(Any, is);
|
||||
|
||||
extern zend_class_entry* any_type;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Upb.
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -910,4 +1061,16 @@ const zend_class_entry* field_type_class(
|
||||
.bucket.obj.object))
|
||||
#endif
|
||||
|
||||
// Message handler
|
||||
static inline zval* php_proto_message_read_property(
|
||||
zval* msg, zval* member PHP_PROTO_TSRMLS_DC) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
return message_handlers->read_property(msg, member, BP_VAR_R,
|
||||
NULL PHP_PROTO_TSRMLS_CC);
|
||||
#else
|
||||
return message_handlers->read_property(msg, member, BP_VAR_R, NULL,
|
||||
NULL PHP_PROTO_TSRMLS_CC);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
|
||||
|
30
php/src/GPBMetadata/Google/Protobuf/Any.php
Normal file
30
php/src/GPBMetadata/Google/Protobuf/Any.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/any.proto
|
||||
|
||||
namespace GPBMetadata\Google\Protobuf;
|
||||
|
||||
class Any
|
||||
{
|
||||
public static $is_initialized = false;
|
||||
|
||||
public static function initOnce() {
|
||||
$pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
|
||||
|
||||
if (static::$is_initialized == true) {
|
||||
return;
|
||||
}
|
||||
$pool->internalAddGeneratedFile(hex2bin(
|
||||
"0acd010a19676f6f676c652f70726f746f6275662f616e792e70726f746f" .
|
||||
"120f676f6f676c652e70726f746f62756622260a03416e7912100a087479" .
|
||||
"70655f75726c180120012809120d0a0576616c756518022001280c426f0a" .
|
||||
"13636f6d2e676f6f676c652e70726f746f6275664208416e7950726f746f" .
|
||||
"50015a256769746875622e636f6d2f676f6c616e672f70726f746f627566" .
|
||||
"2f7074797065732f616e79a20203475042aa021e476f6f676c652e50726f" .
|
||||
"746f6275662e57656c6c4b6e6f776e5479706573620670726f746f33"
|
||||
));
|
||||
|
||||
static::$is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
274
php/src/Google/Protobuf/Any.php
Normal file
274
php/src/Google/Protobuf/Any.php
Normal file
@ -0,0 +1,274 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/any.proto
|
||||
|
||||
namespace Google\Protobuf;
|
||||
|
||||
use Google\Protobuf\Internal\DescriptorPool;
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
use Google\Protobuf\Internal\Message;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
|
||||
/**
|
||||
* `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||
* URL that describes the type of the serialized message.
|
||||
* Protobuf library provides support to pack/unpack Any values in the form
|
||||
* of utility functions or additional generated methods of the Any type.
|
||||
* Example 1: Pack and unpack a message in C++.
|
||||
* Foo foo = ...;
|
||||
* Any any;
|
||||
* any.PackFrom(foo);
|
||||
* ...
|
||||
* if (any.UnpackTo(&foo)) {
|
||||
* ...
|
||||
* }
|
||||
* Example 2: Pack and unpack a message in Java.
|
||||
* Foo foo = ...;
|
||||
* Any any = Any.pack(foo);
|
||||
* ...
|
||||
* if (any.is(Foo.class)) {
|
||||
* foo = any.unpack(Foo.class);
|
||||
* }
|
||||
* Example 3: Pack and unpack a message in Python.
|
||||
* foo = Foo(...)
|
||||
* any = Any()
|
||||
* any.Pack(foo)
|
||||
* ...
|
||||
* if any.Is(Foo.DESCRIPTOR):
|
||||
* any.Unpack(foo)
|
||||
* ...
|
||||
* The pack methods provided by protobuf library will by default use
|
||||
* 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||
* methods only use the fully qualified type name after the last '/'
|
||||
* in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||
* name "y.z".
|
||||
* JSON
|
||||
* ====
|
||||
* The JSON representation of an `Any` value uses the regular
|
||||
* representation of the deserialized, embedded message, with an
|
||||
* additional field `@type` which contains the type URL. Example:
|
||||
* package google.profile;
|
||||
* message Person {
|
||||
* string first_name = 1;
|
||||
* string last_name = 2;
|
||||
* }
|
||||
* {
|
||||
* "@type": "type.googleapis.com/google.profile.Person",
|
||||
* "firstName": <string>,
|
||||
* "lastName": <string>
|
||||
* }
|
||||
* If the embedded message type is well-known and has a custom JSON
|
||||
* representation, that representation will be embedded adding a field
|
||||
* `value` which holds the custom JSON in addition to the `@type`
|
||||
* field. Example (for message [google.protobuf.Duration][]):
|
||||
* {
|
||||
* "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||
* "value": "1.212s"
|
||||
* }
|
||||
*
|
||||
* Generated from protobuf message <code>google.protobuf.Any</code>
|
||||
*/
|
||||
class Any extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* A URL/resource name whose content describes the type of the
|
||||
* serialized protocol buffer message.
|
||||
* For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||
* following restrictions and interpretations apply:
|
||||
* * If no scheme is provided, `https` is assumed.
|
||||
* * The last segment of the URL's path must represent the fully
|
||||
* qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||
* The name should be in a canonical form (e.g., leading "." is
|
||||
* not accepted).
|
||||
* * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
* value in binary format, or produce an error.
|
||||
* * Applications are allowed to cache lookup results based on the
|
||||
* URL, or have them precompiled into a binary to avoid any
|
||||
* lookup. Therefore, binary compatibility needs to be preserved
|
||||
* on changes to types. (Use versioned type names to manage
|
||||
* breaking changes.)
|
||||
* Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
* used with implementation specific semantics.
|
||||
*
|
||||
* Generated from protobuf field <code>string type_url = 1;</code>
|
||||
*/
|
||||
private $type_url = '';
|
||||
/**
|
||||
* Must be a valid serialized protocol buffer of the above specified type.
|
||||
*
|
||||
* Generated from protobuf field <code>bytes value = 2;</code>
|
||||
*/
|
||||
private $value = '';
|
||||
|
||||
const TYPE_URL_PREFIX = 'type.googleapis.com/';
|
||||
|
||||
public function __construct() {
|
||||
\GPBMetadata\Google\Protobuf\Any::initOnce();
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* A URL/resource name whose content describes the type of the
|
||||
* serialized protocol buffer message.
|
||||
* For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||
* following restrictions and interpretations apply:
|
||||
* * If no scheme is provided, `https` is assumed.
|
||||
* * The last segment of the URL's path must represent the fully
|
||||
* qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||
* The name should be in a canonical form (e.g., leading "." is
|
||||
* not accepted).
|
||||
* * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
* value in binary format, or produce an error.
|
||||
* * Applications are allowed to cache lookup results based on the
|
||||
* URL, or have them precompiled into a binary to avoid any
|
||||
* lookup. Therefore, binary compatibility needs to be preserved
|
||||
* on changes to types. (Use versioned type names to manage
|
||||
* breaking changes.)
|
||||
* Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
* used with implementation specific semantics.
|
||||
*
|
||||
* Generated from protobuf field <code>string type_url = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getTypeUrl()
|
||||
{
|
||||
return $this->type_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* A URL/resource name whose content describes the type of the
|
||||
* serialized protocol buffer message.
|
||||
* For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||
* following restrictions and interpretations apply:
|
||||
* * If no scheme is provided, `https` is assumed.
|
||||
* * The last segment of the URL's path must represent the fully
|
||||
* qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||
* The name should be in a canonical form (e.g., leading "." is
|
||||
* not accepted).
|
||||
* * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
* value in binary format, or produce an error.
|
||||
* * Applications are allowed to cache lookup results based on the
|
||||
* URL, or have them precompiled into a binary to avoid any
|
||||
* lookup. Therefore, binary compatibility needs to be preserved
|
||||
* on changes to types. (Use versioned type names to manage
|
||||
* breaking changes.)
|
||||
* Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
* used with implementation specific semantics.
|
||||
*
|
||||
* Generated from protobuf field <code>string type_url = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setTypeUrl($var)
|
||||
{
|
||||
GPBUtil::checkString($var, True);
|
||||
$this->type_url = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be a valid serialized protocol buffer of the above specified type.
|
||||
*
|
||||
* Generated from protobuf field <code>bytes value = 2;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be a valid serialized protocol buffer of the above specified type.
|
||||
*
|
||||
* Generated from protobuf field <code>bytes value = 2;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setValue($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->value = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to resolve the type_url in Any message to get the
|
||||
* targeted message type. If failed, an error will be thrown. Otherwise,
|
||||
* the method will create a message of the targeted type and fill it with
|
||||
* the decoded value in Any.
|
||||
* @return unpacked message
|
||||
* @throws Exception Type url needs to be type.googleapis.com/fully-qulified.
|
||||
* @throws Exception Class hasn't been added to descriptor pool.
|
||||
* @throws Exception cannot decode data in value field.
|
||||
*/
|
||||
public function unpack()
|
||||
{
|
||||
// Get fully qualifed name from type url.
|
||||
$type_url_len = strlen($this->type_url);
|
||||
$url_prifix_len = strlen(Any::TYPE_URL_PREFIX);
|
||||
if ($type_url_len < url_prifix_len ||
|
||||
substr($this->type_url, 0, $url_prifix_len) !=
|
||||
Any::TYPE_URL_PREFIX) {
|
||||
throw new \Exception(
|
||||
"Type url needs to be type.googleapis.com/fully-qulified");
|
||||
}
|
||||
$fully_qualifed_name =
|
||||
substr($this->type_url, $url_prifix_len, $type_url_len);
|
||||
|
||||
// Create message according to fully qualified name.
|
||||
$pool = DescriptorPool::getGeneratedPool();
|
||||
$desc = $pool->getDescriptorByProtoName( ".".$fully_qualifed_name);
|
||||
if (is_null($desc)) {
|
||||
throw new \Exception("Class ".$fully_qualifed_name
|
||||
." hasn't been added to descriptor pool");
|
||||
}
|
||||
$klass = $desc->getClass();
|
||||
$msg = new $klass();
|
||||
|
||||
// Merge data into message.
|
||||
$msg->mergeFromString($this->value);
|
||||
return $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type_url will be created according to the given message’s type and
|
||||
* the value is encoded data from the given message..
|
||||
* @param message: A proto message.
|
||||
*/
|
||||
public function pack($msg)
|
||||
{
|
||||
if (!$msg instanceof Message) {
|
||||
trigger_error("Given parameter is not a message instance.",
|
||||
E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set value using serialzed message.
|
||||
$this->value = $msg->serializeToString();
|
||||
|
||||
// Set type url.
|
||||
$pool = DescriptorPool::getGeneratedPool();
|
||||
$desc = $pool->getDescriptorByClassName(get_class($msg));
|
||||
$fully_qualifed_name = $desc->getFullName();
|
||||
$this->type_url = Any::TYPE_URL_PREFIX.substr(
|
||||
$fully_qualifed_name, 1, strlen($fully_qualifed_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns whether the type_url in any_message is corresponded
|
||||
* to the given class.
|
||||
* @param klass: The fully qualified PHP class name of a proto message type.
|
||||
*/
|
||||
public function is($klass)
|
||||
{
|
||||
$pool = DescriptorPool::getGeneratedPool();
|
||||
$desc = $pool->getDescriptorByClassName($klass);
|
||||
$fully_qualifed_name = $desc->getFullName();
|
||||
$type_url = Any::TYPE_URL_PREFIX.substr(
|
||||
$fully_qualifed_name, 1, strlen($fully_qualifed_name));
|
||||
return $this->type_url === $type_url;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
# gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so `which
|
||||
# phpunit` --bootstrap autoload.php tmp_test.php
|
||||
#
|
||||
gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so `which phpunit` --bootstrap autoload.php encode_decode_test.php
|
||||
gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so `which phpunit` --bootstrap autoload.php well_known_test.php
|
||||
#
|
||||
# gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php
|
||||
#
|
||||
|
@ -1,8 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Google\Protobuf\GPBEmpty;
|
||||
require_once('test_base.php');
|
||||
require_once('test_util.php');
|
||||
|
||||
class WellKnownTest extends PHPUnit_Framework_TestCase {
|
||||
use Google\Protobuf\GPBEmpty;
|
||||
use Google\Protobuf\Any;
|
||||
|
||||
use Foo\TestMessage;
|
||||
|
||||
class NotMessage {}
|
||||
|
||||
class WellKnownTest extends TestBase {
|
||||
|
||||
public function testNone()
|
||||
{
|
||||
@ -14,4 +22,68 @@ class WellKnownTest extends PHPUnit_Framework_TestCase {
|
||||
$msg = new TestImportDescriptorProto();
|
||||
}
|
||||
|
||||
public function testAny()
|
||||
{
|
||||
// Create embed message
|
||||
$embed = new TestMessage();
|
||||
$this->setFields($embed);
|
||||
$data = $embed->serializeToString();
|
||||
|
||||
// Set any via normal setter.
|
||||
$any = new Any();
|
||||
|
||||
$this->assertSame(
|
||||
$any, $any->setTypeUrl("type.googleapis.com/foo.TestMessage"));
|
||||
$this->assertSame("type.googleapis.com/foo.TestMessage",
|
||||
$any->getTypeUrl());
|
||||
|
||||
$this->assertSame($any, $any->setValue($data));
|
||||
$this->assertSame($data, $any->getValue());
|
||||
|
||||
// Test unpack.
|
||||
$msg = $any->unpack();
|
||||
$this->assertTrue($msg instanceof TestMessage);
|
||||
$this->expectFields($msg);
|
||||
|
||||
// Test pack.
|
||||
$any = new Any();
|
||||
$any->pack($embed);
|
||||
$this->assertSame($data, $any->getValue());
|
||||
$this->assertSame("type.googleapis.com/foo.TestMessage", $any->getTypeUrl());
|
||||
|
||||
// Test is.
|
||||
$this->assertTrue($any->is(TestMessage::class));
|
||||
$this->assertFalse($any->is(Any::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Exception
|
||||
*/
|
||||
public function testAnyUnpackInvalidTypeUrl()
|
||||
{
|
||||
$any = new Any();
|
||||
$any->setTypeUrl("invalid");
|
||||
$any->unpack();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Exception
|
||||
*/
|
||||
public function testAnyUnpackMessageNotAdded()
|
||||
{
|
||||
$any = new Any();
|
||||
$any->setTypeUrl("type.googleapis.com/MessageNotAdded");
|
||||
$any->unpack();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Exception
|
||||
*/
|
||||
public function testAnyUnpackDecodeError()
|
||||
{
|
||||
$any = new Any();
|
||||
$any->setTypeUrl("type.googleapis.com/foo.TestMessage");
|
||||
$any->setValue("abc");
|
||||
$any->unpack();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user