Skip to content

Commit 4a5c6d9

Browse files
committed
support magic serialization methods
1 parent 2eb2f41 commit 4a5c6d9

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

msgpack_pack.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ static inline void msgpack_serialize_class(smart_str *buf, zval *val, zval *retv
136136
continue;
137137
}
138138

139+
if (EG(exception)) {
140+
return;
141+
}
142+
139143
if (Z_TYPE_P(value) != IS_STRING) {
140144
ZVAL_DEREF(value);
141145
if (Z_TYPE_P(value) != IS_STRING) {
@@ -288,6 +292,10 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable
288292
if (key_str && incomplete_class && strcmp(ZSTR_VAL(key_str), MAGIC_MEMBER) == 0) {
289293
continue;
290294
}
295+
296+
if (EG(exception)) {
297+
goto done;
298+
}
291299
if (key_str && hash) {
292300
msgpack_serialize_string(buf, ZSTR_VAL(key_str), ZSTR_LEN(key_str));
293301
} else if (hash) {
@@ -330,6 +338,10 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable
330338
continue;
331339
}
332340

341+
if (EG(exception)) {
342+
goto done;
343+
}
344+
333345
if (Z_TYPE_P(data) == IS_REFERENCE) {
334346
data_noref = Z_REFVAL_P(data);
335347
} else {
@@ -356,6 +368,7 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable
356368
}
357369
}
358370
}
371+
done: ;
359372
#if PHP_VERSION_ID >= 70400
360373
if (free_ht && ht) {
361374
zend_array_destroy(ht);
@@ -393,7 +406,37 @@ static inline void msgpack_serialize_object(smart_str *buf, zval *val, HashTable
393406
}
394407
#endif
395408

396-
if (ce && ce->serialize != NULL) {
409+
#if PHP_VERSION_ID >= 70400
410+
if (ce && ce->__serialize) {
411+
zval retval, obj;
412+
413+
ZVAL_OBJ_COPY(&obj, Z_OBJ_P(val_noref));
414+
zend_call_known_instance_method_with_0_params(Z_OBJCE(obj)->__serialize, Z_OBJ(obj), &retval);
415+
416+
if (!EG(exception)) {
417+
if (Z_TYPE(retval) == IS_ARRAY) {
418+
msgpack_pack_map(buf, 2);
419+
420+
msgpack_pack_nil(buf);
421+
msgpack_serialize_string(buf, ZSTR_VAL(ce->name), ZSTR_LEN(ce->name));
422+
msgpack_pack_nil(buf);
423+
msgpack_serialize_zval(buf, &retval, var_hash);
424+
} else {
425+
msgpack_pack_nil(buf);
426+
zend_type_error("%s::__serialize() must return an array", ZSTR_VAL(ce->name));
427+
}
428+
} else {
429+
msgpack_pack_nil(buf);
430+
}
431+
432+
zval_ptr_dtor(&obj);
433+
zval_ptr_dtor(&retval);
434+
PHP_CLEANUP_CLASS_ATTRIBUTES();
435+
return;
436+
}
437+
#endif
438+
439+
if (ce && ce->serialize) {
397440
unsigned char *serialized_data = NULL;
398441
size_t serialized_length;
399442

msgpack_unpack.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -615,25 +615,30 @@ int msgpack_unserialize_map_item(msgpack_unserialize_data *unpack, zval **contai
615615
ZVAL_MAKE_REF(*container);
616616
break;
617617
case MSGPACK_SERIALIZE_TYPE_RECURSIVE:
618-
unpack->type = MSGPACK_SERIALIZE_TYPE_RECURSIVE;
619-
break;
620618
case MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT:
621-
unpack->type = MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT;
622-
break;
623619
case MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE:
624-
unpack->type = MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE;
625-
break;
626620
case MSGPACK_SERIALIZE_TYPE_OBJECT:
627-
unpack->type = MSGPACK_SERIALIZE_TYPE_OBJECT;
621+
unpack->type = Z_LVAL_P(val);
628622
break;
629623
default:
630624
break;
631625
}
632626
} else if (Z_TYPE_P(val) == IS_STRING) {
633-
ce = msgpack_unserialize_class(container, Z_STR_P(val), 1);
634-
if (ce == NULL) {
635-
MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val);
636-
return 0;
627+
msgpack_unserialize_class(container, Z_STR_P(val), 1);
628+
#if PHP_VERSION_ID >= 70400
629+
} else if (Z_TYPE_P(val) == IS_ARRAY) {
630+
if (Z_TYPE_P(*container) == IS_OBJECT && (ce = Z_OBJCE_P(*container)) && ce->__unserialize) {
631+
zval param;
632+
ZVAL_COPY(&param, val);
633+
zend_object *prev_exc = EG(exception);
634+
635+
zend_call_known_instance_method_with_1_params(
636+
ce->__unserialize, Z_OBJ_P(*container), NULL, &param);
637+
if (EG(exception) != prev_exc) {
638+
GC_ADD_FLAGS(Z_OBJ_P(*container), IS_OBJ_DESTRUCTOR_CALLED);
639+
}
640+
zval_ptr_dtor(&param);
641+
#endif
637642
}
638643
}
639644
MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val);
@@ -662,8 +667,8 @@ int msgpack_unserialize_map_item(msgpack_unserialize_data *unpack, zval **contai
662667
ce->unserialize(*container, ce, (const unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val) + 1, NULL);
663668

664669
MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val);
665-
666670
return 0;
671+
667672
case MSGPACK_SERIALIZE_TYPE_RECURSIVE:
668673
case MSGPACK_SERIALIZE_TYPE_OBJECT:
669674
case MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE:
@@ -672,7 +677,7 @@ int msgpack_unserialize_map_item(msgpack_unserialize_data *unpack, zval **contai
672677
int type = unpack->type;
673678

674679
unpack->type = MSGPACK_SERIALIZE_TYPE_NONE;
675-
if ((rval = msgpack_var_access(&unpack->var_hash, Z_LVAL_P(val) - 1)) == NULL) {
680+
if (!(rval = msgpack_var_access(&unpack->var_hash, Z_LVAL_P(val) - 1))) {
676681
if (UNEXPECTED(Z_LVAL_P(val) == 1 /* access the retval */)) {
677682
rval = unpack->retval;
678683
} else {
@@ -688,13 +693,11 @@ int msgpack_unserialize_map_item(msgpack_unserialize_data *unpack, zval **contai
688693
zval_ptr_dtor(*container);
689694
}
690695

691-
ZVAL_COPY_VALUE(*container, rval);
696+
ZVAL_COPY(*container, rval);
692697
if (type == MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE) {
693698
ZVAL_MAKE_REF(*container);
694699
}
695700

696-
Z_TRY_ADDREF_P(*container);
697-
698701
MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val);
699702
return 0;
700703
}

0 commit comments

Comments
 (0)