From 773abe75361852f68ba6c2ec26a945566951dab3 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 1 Mar 2022 14:28:13 +0100 Subject: [PATCH] accept arrays as named parameters for {Uns,S}erializer and {Reader,Writer}\Options --- ion.c | 47 ++++++++++++++++++++++++++++++++----- ion.stub.php | 10 ++++---- ion_arginfo.h | 14 +++++------ tests/Unserializer/PHP.phpt | 7 ++++++ 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/ion.c b/ion.c index b357995..f7758e7 100644 --- a/ion.c +++ b/ion.c @@ -1653,6 +1653,25 @@ static ZEND_METHOD(ion_Writer_Stream_Writer, getStream) RETURN_RES(obj->stream.ptr->res); } +#define Z_PARAM_OBJ_OF_CLASS_OR_NAMED_OR_NULL(obj_dest, iface_ce, impl_ce, arr_dest) \ + Z_PARAM_PROLOGUE(0,0) \ + if (!zend_parse_arg_obj(_arg, &(obj_dest), iface_ce, true)) { \ + if (UNEXPECTED(!zend_parse_arg_array(_arg, &(arr_dest), true, 0))) { \ + _error = (iface_ce)->name->val; \ + _error_code = ZPP_ERROR_WRONG_CLASS_OR_NULL; \ + break; \ + } \ + zval tmp; \ + object_init_ex(&tmp, impl_ce); \ + *(&(obj_dest)) = Z_OBJ(tmp); \ + zend_call_known_function((impl_ce)->constructor, obj_dest, impl_ce, \ + NULL, 0, NULL, Z_ARRVAL_P(arr_dest)); \ + if (EG(exception)) { \ + OBJ_RELEASE(obj_dest); \ + return; \ + } \ + } + static ZEND_METHOD(ion_Serializer_PHP, __construct) { php_ion_serializer_php *obj = php_ion_obj(serializer_php, Z_OBJ_P(ZEND_THIS)); @@ -1660,15 +1679,19 @@ static ZEND_METHOD(ion_Serializer_PHP, __construct) obj->serializer.call_magic = true; + zval *za_opt = NULL; ZEND_PARSE_PARAMETERS_START(0, 4) Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Writer_Options) + Z_PARAM_OBJ_OF_CLASS_OR_NAMED_OR_NULL(obj->opt, ce_Writer_Options, ce_Writer_Options, za_opt) Z_PARAM_BOOL(obj->serializer.multi_seq) Z_PARAM_BOOL(obj->serializer.call_magic) Z_PARAM_STR_OR_NULL(obj->serializer.call_custom) ZEND_PARSE_PARAMETERS_END(); php_ion_serializer_php_ctor(obj); + if (za_opt) { + OBJ_RELEASE(obj->opt); + } } static ZEND_METHOD(ion_Serializer_PHP, serialize) { @@ -1683,12 +1706,12 @@ static ZEND_METHOD(ion_Serializer_PHP, serialize) } static ZEND_FUNCTION(ion_serialize) { - zval *data; + zval *data, *za_ser = NULL; zend_object *zo_ser = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ZVAL(data) Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(zo_ser, ce_Serializer) + Z_PARAM_OBJ_OF_CLASS_OR_NAMED_OR_NULL(zo_ser, ce_Serializer, ce_Serializer_PHP, za_ser) ZEND_PARSE_PARAMETERS_END(); if (!zo_ser || zo_ser->ce == ce_Serializer_PHP) { @@ -1698,6 +1721,10 @@ static ZEND_FUNCTION(ion_serialize) } else { zend_call_method_with_1_params(zo_ser, NULL, NULL, "serialize", return_value, data); } + + if (za_ser) { + OBJ_RELEASE(zo_ser); + } } static ZEND_METHOD(ion_Unserializer_PHP, __construct) @@ -1707,15 +1734,19 @@ static ZEND_METHOD(ion_Unserializer_PHP, __construct) obj->unserializer.call_magic = true; + zval *za_opt = NULL; ZEND_PARSE_PARAMETERS_START(0, 4) Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Reader_Options) + Z_PARAM_OBJ_OF_CLASS_OR_NAMED_OR_NULL(obj->opt, ce_Reader_Options, ce_Reader_Options, za_opt) Z_PARAM_BOOL(obj->unserializer.multi_seq) Z_PARAM_BOOL(obj->unserializer.call_magic) Z_PARAM_STR_OR_NULL(obj->unserializer.call_custom) ZEND_PARSE_PARAMETERS_END(); php_ion_unserializer_php_ctor(obj); + if (za_opt) { + OBJ_RELEASE(obj->opt); + } } static ZEND_METHOD(ion_Unserializer_PHP, unserialize) { @@ -1730,12 +1761,12 @@ static ZEND_METHOD(ion_Unserializer_PHP, unserialize) } static ZEND_FUNCTION(ion_unserialize) { - zval *data; + zval *data, *za_ser = NULL; zend_object *zo_ser = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ZVAL(data) Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(zo_ser, ce_Unserializer) + Z_PARAM_OBJ_OF_CLASS_OR_NAMED_OR_NULL(zo_ser, ce_Unserializer, ce_Unserializer_PHP, za_ser) ZEND_PARSE_PARAMETERS_END(); if (!zo_ser || zo_ser->ce == ce_Unserializer_PHP) { @@ -1745,6 +1776,10 @@ static ZEND_FUNCTION(ion_unserialize) } else { zend_call_method_with_1_params(zo_ser, NULL, NULL, "unserialize", return_value, data); } + + if (za_ser) { + OBJ_RELEASE(zo_ser); + } } PHP_RINIT_FUNCTION(ion) diff --git a/ion.stub.php b/ion.stub.php index 37bb8e0..9431b17 100644 --- a/ion.stub.php +++ b/ion.stub.php @@ -28,11 +28,11 @@ namespace ion; * * object (incl. \Serializable, and classes implementing magic and custom __serialize) * * @param mixed $data PHP value(s). - * @param Serializer|null $serializer Custom serializer. + * @param Serializer|array|null $serializer Custom serializer. * @return string serialized ION data * @throws \ion\Exception */ -function serialize(mixed $data, ?Serializer $serializer = null) : string {} +function serialize(mixed $data, Serializer|array|null $serializer = null) : string {} /** * Unserialize ION data (stream) as PHP value(s). @@ -41,7 +41,7 @@ function serialize(mixed $data, ?Serializer $serializer = null) : string {} * @return mixed unserialized PHP values * @throws \ion\Exception */ -function unserialize($data, ?Unserializer $unserializer = null) : mixed {} +function unserialize($data, Unserializer|array|null $unserializer = null) : mixed {} /** * Serializer interface, used to customize ion\serialize()'s behavior. @@ -1055,7 +1055,7 @@ class PHP implements \ion\Serializer { /** * Writer options. */ - public readonly ?\ion\Writer\Options $writerOptions = null, + public readonly \ion\Writer\Options|array|null $writerOptions = null, /** * Whether to write the top level array as multiple ION sequences. */ @@ -1086,7 +1086,7 @@ class PHP implements \ion\Unserializer { /** * Reader options. */ - public readonly ?\ion\Reader\Options $readerOptions = null, + public readonly \ion\Reader\Options|array|null $readerOptions = null, /** * Whether to continue reading multiple ION sequences after the first one. */ diff --git a/ion_arginfo.h b/ion_arginfo.h index 0af9a51..a3122ac 100644 --- a/ion_arginfo.h +++ b/ion_arginfo.h @@ -1,14 +1,14 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f45c86044a99ab4db187da808bdd5cdfdb7e5a26 */ + * Stub hash: 7fcf22ba2096fdecb7319e7a399dbccbb21f89d9 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ion_serialize, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, data, IS_MIXED, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, serializer, ion\\Serializer, 1, "null") + ZEND_ARG_OBJ_TYPE_MASK(0, serializer, ion\\Serializer, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ion_unserialize, 0, 1, IS_MIXED, 0) ZEND_ARG_INFO(0, data) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, unserializer, ion\\Unserializer, 1, "null") + ZEND_ARG_OBJ_TYPE_MASK(0, unserializer, ion\\Unserializer, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Serializer_serialize, 0, 1, IS_STRING, 0) @@ -506,7 +506,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_ion_Writer_Stream_Writer_getStream arginfo_class_ion_Catalog___construct ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Serializer_PHP___construct, 0, 0, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, writerOptions, ion\\Writer\\Options, 1, "null") + ZEND_ARG_OBJ_TYPE_MASK(0, writerOptions, ion\\Writer\\Options, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, multiSequence, _IS_BOOL, 0, "false") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callMagicSerialize, _IS_BOOL, 0, "true") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callCustomSerialize, IS_STRING, 1, "null") @@ -515,7 +515,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_ion_Serializer_PHP_serialize arginfo_class_ion_Serializer_serialize ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Unserializer_PHP___construct, 0, 0, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, readerOptions, ion\\Reader\\Options, 1, "null") + ZEND_ARG_OBJ_TYPE_MASK(0, readerOptions, ion\\Reader\\Options, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, multiSequence, _IS_BOOL, 0, "false") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callMagicUnserialize, _IS_BOOL, 0, "true") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callCustomUnserialize, IS_STRING, 1, "null") @@ -1895,7 +1895,7 @@ static zend_class_entry *register_class_ion_Serializer_PHP(zend_class_entry *cla zval property_writerOptions_default_value; ZVAL_UNDEF(&property_writerOptions_default_value); zend_string *property_writerOptions_name = zend_string_init("writerOptions", sizeof("writerOptions") - 1, 1); - zend_declare_typed_property(class_entry, property_writerOptions_name, &property_writerOptions_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_writerOptions_class_ion_Writer_Options, 0, MAY_BE_NULL)); + zend_declare_typed_property(class_entry, property_writerOptions_name, &property_writerOptions_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_writerOptions_class_ion_Writer_Options, 0, MAY_BE_ARRAY|MAY_BE_NULL)); zend_string_release(property_writerOptions_name); zval property_multiSequence_default_value; @@ -1931,7 +1931,7 @@ static zend_class_entry *register_class_ion_Unserializer_PHP(zend_class_entry *c zval property_readerOptions_default_value; ZVAL_UNDEF(&property_readerOptions_default_value); zend_string *property_readerOptions_name = zend_string_init("readerOptions", sizeof("readerOptions") - 1, 1); - zend_declare_typed_property(class_entry, property_readerOptions_name, &property_readerOptions_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_readerOptions_class_ion_Reader_Options, 0, MAY_BE_NULL)); + zend_declare_typed_property(class_entry, property_readerOptions_name, &property_readerOptions_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_readerOptions_class_ion_Reader_Options, 0, MAY_BE_ARRAY|MAY_BE_NULL)); zend_string_release(property_readerOptions_name); zval property_multiSequence_default_value; diff --git a/tests/Unserializer/PHP.phpt b/tests/Unserializer/PHP.phpt index 3d7f290..99cef03 100644 --- a/tests/Unserializer/PHP.phpt +++ b/tests/Unserializer/PHP.phpt @@ -8,9 +8,16 @@ TEST $o1 = ion\unserialize("[foo,{p:1}]"); $o2 = ion\unserialize("[foo,{p:1}]", $u1 = new ion\Unserializer\PHP); $o3 = ion\unserialize("[foo,{p:1}]", $u2 = new ion\Unserializer\PHP(new ion\Reader\Options)); +$o4 = ion\unserialize("[foo,{p:1}]", ["readerOptions" => []]); if ($o1 != $o2) { var_dump($o1, $o2); } +if ($o1 != $o3) { + var_dump($o1, $o3); +} +if ($o1 != $o4) { + var_dump($o1, $o4); +} var_dump($u1); if ($u1 != $u2) { var_dump($u2); -- 2.30.2