Skip to content

Commit 5a05531

Browse files
committed
support magic serialization methods
1 parent fd1f666 commit 5a05531

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) {
@@ -290,6 +294,10 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable
290294
if (key_str && incomplete_class && strcmp(ZSTR_VAL(key_str), MAGIC_MEMBER) == 0) {
291295
continue;
292296
}
297+
298+
if (EG(exception)) {
299+
goto done;
300+
}
293301
if (key_str && hash) {
294302
msgpack_serialize_string(buf, ZSTR_VAL(key_str), ZSTR_LEN(key_str));
295303
} else if (hash) {
@@ -332,6 +340,10 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable
332340
continue;
333341
}
334342

343+
if (EG(exception)) {
344+
goto done;
345+
}
346+
335347
if (Z_TYPE_P(data) == IS_REFERENCE) {
336348
data_noref = Z_REFVAL_P(data);
337349
} else {
@@ -358,6 +370,7 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable
358370
}
359371
}
360372
}
373+
done: ;
361374
#if PHP_VERSION_ID >= 70400
362375
if (free_ht && ht) {
363376
zend_array_destroy(ht);
@@ -395,7 +408,37 @@ static inline void msgpack_serialize_object(smart_str *buf, zval *val, HashTable
395408
}
396409
#endif
397410

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

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)