in lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp [507:672]
void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval* return_value, HashTable* fieldspec) {
ZVAL_NULL(return_value);
switch (thrift_typeID) {
case T_STOP:
case T_VOID:
RETURN_NULL();
return;
case T_STRUCT: {
zval* val_ptr = zend_hash_str_find(fieldspec, "class", sizeof("class")-1);
if (val_ptr == nullptr) {
throw_tprotocolexception("no class type in spec", INVALID_DATA);
skip_element(T_STRUCT, transport);
RETURN_NULL();
}
char* structType = Z_STRVAL_P(val_ptr);
// Create an object in PHP userland based on our spec
createObject(structType, return_value);
if (Z_TYPE_P(return_value) == IS_NULL) {
// unable to create class entry
skip_element(T_STRUCT, transport);
RETURN_NULL();
}
zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false);
ZVAL_DEREF(spec);
if (EG(exception)) {
zend_object *ex = EG(exception);
EG(exception) = nullptr;
throw PHPExceptionWrapper(ex);
}
if (Z_TYPE_P(spec) != IS_ARRAY) {
char errbuf[128];
snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType, Z_TYPE_P(spec));
throw_tprotocolexception(errbuf, INVALID_DATA);
RETURN_NULL();
}
binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec));
return;
} break;
case T_BOOL: {
uint8_t c;
transport.readBytes(&c, 1);
RETURN_BOOL(c != 0);
}
//case T_I08: // same numeric value as T_BYTE
case T_BYTE: {
uint8_t c;
transport.readBytes(&c, 1);
RETURN_LONG((int8_t)c);
}
case T_I16: {
uint16_t c;
transport.readBytes(&c, 2);
RETURN_LONG((int16_t)ntohs(c));
}
case T_I32: {
uint32_t c;
transport.readBytes(&c, 4);
RETURN_LONG((int32_t)ntohl(c));
}
case T_U64:
case T_I64: {
uint64_t c;
transport.readBytes(&c, 8);
RETURN_LONG((int64_t)ntohll(c));
}
case T_DOUBLE: {
union {
uint64_t c;
double d;
} a;
transport.readBytes(&(a.c), 8);
a.c = ntohll(a.c);
RETURN_DOUBLE(a.d);
}
//case T_UTF7: // aliases T_STRING
case T_UTF8:
case T_UTF16:
case T_STRING: {
uint32_t size = transport.readU32();
if (size) {
char strbuf[size+1];
transport.readBytes(strbuf, size);
strbuf[size] = '\0';
ZVAL_STRINGL(return_value, strbuf, size);
} else {
ZVAL_EMPTY_STRING(return_value);
}
return;
}
case T_MAP: { // array of key -> value
uint8_t types[2];
transport.readBytes(types, 2);
uint32_t size = transport.readU32();
array_init(return_value);
zval *val_ptr;
val_ptr = zend_hash_str_find(fieldspec, "key", sizeof("key")-1);
HashTable* keyspec = Z_ARRVAL_P(val_ptr);
val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1);
HashTable* valspec = Z_ARRVAL_P(val_ptr);
for (uint32_t s = 0; s < size; ++s) {
zval key, value;
binary_deserialize(types[0], transport, &key, keyspec);
binary_deserialize(types[1], transport, &value, valspec);
if (Z_TYPE(key) == IS_LONG) {
zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value);
} else {
if (Z_TYPE(key) != IS_STRING) convert_to_string(&key);
zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value);
}
zval_dtor(&key);
}
return; // return_value already populated
}
case T_LIST: { // array with autogenerated numeric keys
int8_t type = transport.readI8();
uint32_t size = transport.readU32();
zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1);
HashTable* elemspec = Z_ARRVAL_P(val_ptr);
array_init(return_value);
for (uint32_t s = 0; s < size; ++s) {
zval value;
binary_deserialize(type, transport, &value, elemspec);
zend_hash_next_index_insert(Z_ARR_P(return_value), &value);
}
return;
}
case T_SET: { // array of key -> TRUE
uint8_t type;
uint32_t size;
transport.readBytes(&type, 1);
transport.readBytes(&size, 4);
size = ntohl(size);
zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1);
HashTable* elemspec = Z_ARRVAL_P(val_ptr);
array_init(return_value);
for (uint32_t s = 0; s < size; ++s) {
zval key, value;
ZVAL_TRUE(&value);
binary_deserialize(type, transport, &key, elemspec);
if (Z_TYPE(key) == IS_LONG) {
zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value);
} else {
if (Z_TYPE(key) != IS_STRING) convert_to_string(&key);
zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value);
}
zval_dtor(&key);
}
return;
}
};
char errbuf[128];
sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID);
throw_tprotocolexception(errbuf, INVALID_DATA);
}