From 93fe730f6968061a52b5e11c097e6521622d78b9 Mon Sep 17 00:00:00 2001 From: Niklas Seyfarth Date: Thu, 11 Apr 2024 10:07:25 +0200 Subject: [PATCH] #171 Add serialization and deserialization support for PHP 8.1 Enums. --- msgpack_pack.c | 17 +++++++++++++++++ msgpack_pack.h | 1 + msgpack_unpack.c | 25 +++++++++++++++++++++++++ tests/issue171.phpt | 31 +++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 tests/issue171.phpt diff --git a/msgpack_pack.c b/msgpack_pack.c index b2a048b..9650a34 100644 --- a/msgpack_pack.c +++ b/msgpack_pack.c @@ -6,6 +6,10 @@ #include "ext/standard/php_incomplete_class.h" #include "ext/standard/php_var.h" +#if PHP_VERSION_ID >= 80100 +#include "Zend/zend_enum.h" +#endif + #include "php_msgpack.h" #include "msgpack_pack.h" #include "msgpack_errors.h" @@ -408,6 +412,19 @@ static inline void msgpack_serialize_object(smart_str *buf, zval *val, HashTable PHP_CLEANUP_CLASS_ATTRIBUTES(); return; } + if (ce && (ce->ce_flags & ZEND_ACC_ENUM)) { + zval *enum_case_name = zend_enum_fetch_case_name(Z_OBJ_P(val_noref)); + msgpack_pack_map(buf, 2); + + msgpack_pack_nil(buf); + msgpack_pack_long(buf, MSGPACK_SERIALIZE_TYPE_ENUM); + + msgpack_serialize_string(buf, ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)); + msgpack_serialize_string(buf, Z_STRVAL_P(enum_case_name), Z_STRLEN_P(enum_case_name)); + + PHP_CLEANUP_CLASS_ATTRIBUTES(); + return; + } #endif #if PHP_VERSION_ID >= 70400 diff --git a/msgpack_pack.h b/msgpack_pack.h index 23fd88c..a1a7e89 100644 --- a/msgpack_pack.h +++ b/msgpack_pack.h @@ -19,6 +19,7 @@ enum msgpack_serialize_type MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT, MSGPACK_SERIALIZE_TYPE_OBJECT, MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE, + MSGPACK_SERIALIZE_TYPE_ENUM, }; void msgpack_serialize_var_init(msgpack_serialize_data_t *var_hash); diff --git a/msgpack_unpack.c b/msgpack_unpack.c index 2589969..f9d0663 100644 --- a/msgpack_unpack.c +++ b/msgpack_unpack.c @@ -2,6 +2,10 @@ #include "php_ini.h" #include "ext/standard/php_incomplete_class.h" +#if PHP_VERSION_ID >= 80100 +#include "Zend/zend_enum.h" +#endif + #include "php_msgpack.h" #include "msgpack_pack.h" #include "msgpack_unpack.h" @@ -617,6 +621,7 @@ int msgpack_unserialize_map_item(msgpack_unpack_data *unpack, zval **container, case MSGPACK_SERIALIZE_TYPE_CUSTOM_OBJECT: case MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE: case MSGPACK_SERIALIZE_TYPE_OBJECT: + case MSGPACK_SERIALIZE_TYPE_ENUM: unpack->type = Z_LVAL_P(val); break; default: @@ -674,6 +679,26 @@ int msgpack_unserialize_map_item(msgpack_unpack_data *unpack, zval **container, return 0; } + case MSGPACK_SERIALIZE_TYPE_ENUM: + { + if (Z_TYPE_P(key) != IS_STRING) { + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); + return MSGPACK_UNPACK_PARSE_ERROR; + } + +#if PHP_VERSION_ID < 80100 + MSGPACK_WARNING( + "[msgpack] (%s) Class %s is an Enum and not supported below PHP 8.1", + __FUNCTION__, Z_STRVAL_P(key)); +#else + ce = msgpack_unserialize_class(container, Z_STR_P(key), 0); + zend_object *enum_instance = zend_enum_get_case(ce, Z_STR_P(val)); + ZVAL_OBJ(*container, enum_instance); +#endif + MSGPACK_UNSERIALIZE_FINISH_MAP_ITEM(unpack, key, val); + return 0; + } + case MSGPACK_SERIALIZE_TYPE_RECURSIVE: case MSGPACK_SERIALIZE_TYPE_OBJECT: case MSGPACK_SERIALIZE_TYPE_OBJECT_REFERENCE: diff --git a/tests/issue171.phpt b/tests/issue171.phpt new file mode 100644 index 0000000..7a61ac0 --- /dev/null +++ b/tests/issue171.phpt @@ -0,0 +1,31 @@ +--TEST-- +Issue #171 (Serializing & Unserializing Enum) +--SKIPIF-- + +--FILE-- +Test + +OK +--EXPECT-- +Test +string(36) "82c006a854657374456e756da54f54484552" +enum(TestEnum::OTHER) +OK