From ea1ee1c4d6c25e31d265554cb71e08a2731f5532 Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Thu, 8 May 2025 01:08:39 +0300 Subject: [PATCH 01/11] Intl: Add IntlListFormatter class --- ext/intl/config.m4 | 3 + ext/intl/listformatter/listformatter.stub.php | 49 ++++ .../listformatter/listformatter_arginfo.h | 77 +++++++ ext/intl/listformatter/listformatter_class.c | 217 ++++++++++++++++++ ext/intl/listformatter/listformatter_class.h | 55 +++++ ext/intl/listformatter/listformatter_data.c | 48 ++++ ext/intl/listformatter/listformatter_data.h | 35 +++ ext/intl/php_intl.c | 5 + .../listformatter/listformatter_basic.phpt | 32 +++ .../listformatter/listformatter_error.phpt | 36 +++ .../listformatter_with_paramaters.phpt | 169 ++++++++++++++ 11 files changed, 726 insertions(+) create mode 100644 ext/intl/listformatter/listformatter.stub.php create mode 100644 ext/intl/listformatter/listformatter_arginfo.h create mode 100644 ext/intl/listformatter/listformatter_class.c create mode 100644 ext/intl/listformatter/listformatter_class.h create mode 100644 ext/intl/listformatter/listformatter_data.c create mode 100644 ext/intl/listformatter/listformatter_data.h create mode 100644 ext/intl/tests/listformatter/listformatter_basic.phpt create mode 100644 ext/intl/tests/listformatter/listformatter_error.phpt create mode 100644 ext/intl/tests/listformatter/listformatter_with_paramaters.phpt diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 index 6a64f0f718100..0feb0509b7eda 100644 --- a/ext/intl/config.m4 +++ b/ext/intl/config.m4 @@ -39,6 +39,8 @@ if test "$PHP_INTL" != "no"; then locale/locale_class.c locale/locale_methods.c locale/locale.c + listformatter/listformatter_class.c + listformatter/listformatter_data.c msgformat/msgformat_attr.c msgformat/msgformat_class.c msgformat/msgformat_data.c @@ -119,6 +121,7 @@ if test "$PHP_INTL" != "no"; then $ext_builddir/grapheme $ext_builddir/idn $ext_builddir/locale + $ext_builddir/listformatter $ext_builddir/msgformat $ext_builddir/normalizer $ext_builddir/resourcebundle diff --git a/ext/intl/listformatter/listformatter.stub.php b/ext/intl/listformatter/listformatter.stub.php new file mode 100644 index 0000000000000..e5b7815307c03 --- /dev/null +++ b/ext/intl/listformatter/listformatter.stub.php @@ -0,0 +1,49 @@ + | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_intl.h" +#include +#include "listformatter_arginfo.h" +#include "listformatter_class.h" +#include "intl_convert.h" + + +static zend_object_handlers listformatter_handlers; + +/* {{{ listformatter_free_obj */ +static void listformatter_free_obj(zend_object *object) +{ + ListFormatter_object *obj = php_intl_listformatter_fetch_object(object); + listformatter_data_free(&obj->lf_data); + zend_object_std_dtor(&obj->zo); +} +/* }}} */ + +/* {{{ listformatter_create_object */ +static zend_object *listformatter_create_object(zend_class_entry *class_type) +{ + ListFormatter_object *obj; + obj = zend_object_alloc(sizeof(ListFormatter_object), class_type); + listformatter_data_init(&obj->lf_data); + zend_object_std_init(&obj->zo, class_type); + object_properties_init(&obj->zo, class_type); + obj->zo.handlers = &listformatter_handlers; + return &obj->zo; +} +/* }}} */ + +/* {{{ listformatter_create_object */ +PHP_METHOD(IntlListFormatter, __construct) +{ + ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); + zend_string *locale; + zend_long type = ULISTFMT_TYPE_AND; + zend_long width = ULISTFMT_WIDTH_WIDE; + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_STR(locale) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(type) + Z_PARAM_LONG(width) + ZEND_PARSE_PARAMETERS_END(); + + if (strlen(uloc_getISO3Language(ZSTR_VAL(locale))) == 0) { + zend_argument_value_error(1, "\"%s\" is invalid", ZSTR_VAL(locale)); + RETURN_THROWS(); + } + + UErrorCode status = U_ZERO_ERROR; + if (U_ICU_VERSION_MAJOR_NUM >= 67) { + + LISTFORMATTER_OBJECT(obj) = ulistfmt_openForType(ZSTR_VAL(locale), type, width, &status); + } else { + if (type != ULISTFMT_TYPE_AND) { + zend_argument_value_error(2, "ICU 66 and below only support IntlListFormatter::TYPE_AND"); + RETURN_THROWS(); + } + + if (width != ULISTFMT_WIDTH_WIDE) { + zend_argument_value_error(3, "ICU 66 and below only support IntlListFormatter::WIDTH_WIDE"); + RETURN_THROWS(); + } + + LISTFORMATTER_OBJECT(obj) = ulistfmt_open(ZSTR_VAL(locale), &status); + } + if (U_FAILURE(status)) { + intl_error_set(NULL, status, "Constructor failed", 0); + zend_throw_exception(IntlException_ce_ptr, "Constructor failed", 0); + RETURN_THROWS(); + } +} +/* }}} */ + +/* {{{ listformatter_format */ +PHP_METHOD(IntlListFormatter, format) +{ + ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); + zval *strings; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(strings) + ZEND_PARSE_PARAMETERS_END(); + + if (!LISTFORMATTER_OBJECT(obj)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "ListFormatter not properly constructed", 0); + RETURN_FALSE; + } + + HashTable *ht = Z_ARRVAL_P(strings); + uint32_t count = zend_array_count(ht); + if (count == 0) { + RETURN_EMPTY_STRING(); + } + + const UChar **items = (const UChar **)safe_emalloc(count, sizeof(const UChar *), 0); + int32_t *itemLengths = (int32_t *)safe_emalloc(count, sizeof(int32_t), 0); + uint32_t i = 0; + zval *val; + + ZEND_HASH_FOREACH_VAL(ht, val) { + zend_string *str_val; + + str_val = zval_get_string(val); + + // Convert PHP string to UTF-16 + UChar *ustr = NULL; + int32_t ustr_len = 0; + UErrorCode status = U_ZERO_ERROR; + + intl_convert_utf8_to_utf16(&ustr, &ustr_len, ZSTR_VAL(str_val), ZSTR_LEN(str_val), &status); + if (U_FAILURE(status)) { + efree(items); + efree(itemLengths); + zend_string_release(str_val); + intl_error_set(NULL, status, "Failed to convert string to UTF-16", 0); + RETURN_FALSE; + } + + items[i] = ustr; + itemLengths[i] = ustr_len; + zend_string_release(str_val); + i++; + } ZEND_HASH_FOREACH_END(); + + UErrorCode status = U_ZERO_ERROR; + int32_t resultLength; + UChar *result = NULL; + + resultLength = ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, NULL, 0, &status); + + if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) { + intl_error_set(NULL, status, "Failed to format list", 0); + RETURN_FALSE; + } + + // Allocate buffer and try again + status = U_ZERO_ERROR; + result = (UChar *)emalloc((resultLength + 1) * sizeof(UChar)); + ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, result, resultLength, &status); + + // Clean up input strings + for (i = 0; i < count; i++) { + efree((void *)items[i]); + } + efree(items); + efree(itemLengths); + + if (U_FAILURE(status)) { + if (result) { + efree(result); + } + intl_error_set(NULL, status, "Failed to format list", 0); + RETURN_FALSE; + } + + // Convert result back to UTF-8 + zend_string *ret = intl_convert_utf16_to_utf8(result, resultLength, &status); + efree(result); + + if (!ret) { + intl_error_set(NULL, status, "Failed to convert result to UTF-8", 0); + RETURN_FALSE; + } + + RETURN_STR(ret); +} +/* }}} */ + +/* {{{ listformatter_getErrorCode */ +PHP_METHOD(IntlListFormatter, getErrorCode) +{ + ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); + + UErrorCode status = intl_error_get_code(LISTFORMATTER_ERROR_P(obj)); + + RETURN_LONG(status); +} +/* }}} */ + +/* {{{ listformatter_getErrorMessage */ +PHP_METHOD(IntlListFormatter, getErrorMessage) +{ + ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); + + zend_string *message = intl_error_get_message(LISTFORMATTER_ERROR_P(obj)); + RETURN_STR(message); +} +/* }}} */ + +/* {{{ listformatter_register_class */ +void listformatter_register_class(void) +{ + zend_class_entry *class_entry = register_class_IntlListFormatter(); + class_entry->create_object = listformatter_create_object; + + memcpy(&listformatter_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + listformatter_handlers.offset = XtOffsetOf(ListFormatter_object, zo); + listformatter_handlers.free_obj = listformatter_free_obj; +} +/* }}} */ diff --git a/ext/intl/listformatter/listformatter_class.h b/ext/intl/listformatter/listformatter_class.h new file mode 100644 index 0000000000000..b6183c9f9eff9 --- /dev/null +++ b/ext/intl/listformatter/listformatter_class.h @@ -0,0 +1,55 @@ +/* + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bogdan Ungureanu | + +----------------------------------------------------------------------+ +*/ + +#ifndef LISTFORMATTER_CLASS_H +#define LISTFORMATTER_CLASS_H + +#include + +#include "intl_common.h" +#include "intl_error.h" +#include "intl_data.h" +#include "listformatter_data.h" + +typedef struct { + listformatter_data lf_data; + zend_object zo; +} ListFormatter_object; + +static inline ListFormatter_object *php_intl_listformatter_fetch_object(zend_object *obj) { + return (ListFormatter_object *)((char*)(obj) - XtOffsetOf(ListFormatter_object, zo)); +} +#define Z_INTL_LISTFORMATTER_P(zv) php_intl_listformatter_fetch_object(Z_OBJ_P(zv)) + +#define LISTFORMATTER_ERROR(lfo) (lfo)->lf_data.error +#define LISTFORMATTER_ERROR_P(lfo) &(LISTFORMATTER_ERROR(lfo)) + +#define LISTFORMATTER_ERROR_CODE(lfo) INTL_ERROR_CODE(LISTFORMATTER_ERROR(lfo)) +#define LISTFORMATTER_ERROR_CODE_P(lfo) &(INTL_ERROR_CODE(LISTFORMATTER_ERROR(lfo))) + +#define LISTFORMATTER_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(ListFormatter, lfo) +#define LISTFORMATTER_OBJECT(lfo) (lfo)->lf_data.ulistfmt +#define LISTFORMATTER_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(INTL_LISTFORMATTER, lfo) +#define LISTFORMATTER_METHOD_FETCH_OBJECT \ + LISTFORMATTER_METHOD_FETCH_OBJECT_NO_CHECK; \ + if (LISTFORMATTER_OBJECT(lfo) == NULL) \ + { \ + zend_throw_error(NULL, "Found unconstructed ListFormatter"); \ + RETURN_THROWS(); \ + } + +void listformatter_register_class( void ); +extern zend_class_entry *ListFormatter_ce_ptr; + +#endif // LISTFORMATTER_CLASS_H \ No newline at end of file diff --git a/ext/intl/listformatter/listformatter_data.c b/ext/intl/listformatter/listformatter_data.c new file mode 100644 index 0000000000000..0cf1f08389db3 --- /dev/null +++ b/ext/intl/listformatter/listformatter_data.c @@ -0,0 +1,48 @@ +/* + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bogdan Ungureanu | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "listformatter_data.h" + +/* {{{ void listformatter_data_init( listformatter_data* lf_data ) + * Initialize internals of listformatter_data. + */ +void listformatter_data_init( listformatter_data* lf_data ) +{ + if( !lf_data ) + return; + + lf_data->ulistfmt = NULL; + intl_error_reset( &lf_data->error ); +} +/* }}} */ + +/* {{{ void listformatter_data_free( listformatter_data* lf_data ) + * Clean up mem allocated by internals of listformatter_data + */ +void listformatter_data_free( listformatter_data* lf_data ) +{ + if( !lf_data ) + return; + + if( lf_data->ulistfmt ) + ulistfmt_close( lf_data->ulistfmt ); + + lf_data->ulistfmt = NULL; + intl_error_reset( &lf_data->error ); +} +/* }}} */ diff --git a/ext/intl/listformatter/listformatter_data.h b/ext/intl/listformatter/listformatter_data.h new file mode 100644 index 0000000000000..ae558b79f3306 --- /dev/null +++ b/ext/intl/listformatter/listformatter_data.h @@ -0,0 +1,35 @@ +/* + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bogdan Ungureanu | + +----------------------------------------------------------------------+ +*/ + +#ifndef LISTFORMATTER_DATA_H +#define LISTFORMATTER_DATA_H + +#include + +#include + +#include "intl_error.h" + +typedef struct { + // error handling + intl_error error; + + // formatter handling + UListFormatter* ulistfmt; +} listformatter_data; + +void listformatter_data_init( listformatter_data* lf_data ); +void listformatter_data_free( listformatter_data* lf_data ); + +#endif // LISTFORMATTER_DATA_H \ No newline at end of file diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index cba18f5ae07b1..68fd2dedfba85 100644 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -41,6 +41,8 @@ #include "locale/locale.h" #include "locale/locale_class.h" +#include "listformatter/listformatter_class.h" + #include "dateformat/dateformat.h" #include "dateformat/dateformat_class.h" #include "dateformat/dateformat_data.h" @@ -156,6 +158,9 @@ PHP_MINIT_FUNCTION( intl ) /* Register 'NumberFormatter' PHP class */ formatter_register_class( ); + /* Register 'ListFormatter' PHP class */ + listformatter_register_class( ); + /* Register 'Normalizer' PHP class */ normalizer_register_Normalizer_class( ); diff --git a/ext/intl/tests/listformatter/listformatter_basic.phpt b/ext/intl/tests/listformatter/listformatter_basic.phpt new file mode 100644 index 0000000000000..d9130efe86d15 --- /dev/null +++ b/ext/intl/tests/listformatter/listformatter_basic.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlListFormatter: Basic functionality +--EXTENSIONS-- +intl +--FILE-- +format([1,2,3]); +echo PHP_EOL; +$formatter = new IntlListFormatter('EN_US'); +echo $formatter->format([1,2,3]); + +echo PHP_EOL . 'FR' . PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); +echo $formatter->format([1,2,3]); +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR'); +echo $formatter->format([1,2,3]); +echo PHP_EOL; + +--EXPECT-- +EN_US +1, 2, and 3 +1, 2, and 3 +FR +1, 2 et 3 +1, 2 et 3 \ No newline at end of file diff --git a/ext/intl/tests/listformatter/listformatter_error.phpt b/ext/intl/tests/listformatter/listformatter_error.phpt new file mode 100644 index 0000000000000..36c943bd61dca --- /dev/null +++ b/ext/intl/tests/listformatter/listformatter_error.phpt @@ -0,0 +1,36 @@ +--TEST-- +IntlListFormatter: error messages +--EXTENSIONS-- +intl +--FILE-- +getMessage(); +} + +echo PHP_EOL; + +try { + $formatter = new IntlListFormatter('ro', IntlListFormatter::TYPE_AND, 23); +} catch (IntlException $exception) { + echo $exception->getMessage() .PHP_EOL; + echo intl_get_error_code(); +} + +$formatter = new IntlListFormatter('ro', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); + +echo PHP_EOL; +try { + echo $formatter->format([new stdClass()]); +} catch(Error $error) { + echo $error->getMessage(); +} + +--EXPECT-- +IntlListFormatter::__construct(): Argument #1 ($locale) "f" is invalid +Constructor failed +1 +Object of class stdClass could not be converted to string \ No newline at end of file diff --git a/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt new file mode 100644 index 0000000000000..a20267f64498e --- /dev/null +++ b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt @@ -0,0 +1,169 @@ +--TEST-- +IntlListFormatter: Test AND, OR and Width parameters +--EXTENSIONS-- +intl +--FILE-- +format([1,2,3]); +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL . 'GB' . PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL . 'FR' . PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT); +echo $formatter->format([1,2,3]); + +echo PHP_EOL; + +$formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW); +echo $formatter->format([1,2,3]); +--EXPECT-- +EN_US +1, 2, and 3 +1, 2, & 3 +1, 2, 3 +1, 2, or 3 +1, 2, or 3 +1, 2, or 3 +1, 2, 3 +1, 2, 3 +1 2 3 +GB +1, 2 and 3 +1, 2 and 3 +1, 2, 3 +1, 2 or 3 +1, 2 or 3 +1, 2 or 3 +1, 2, 3 +1, 2, 3 +1 2 3 +FR +1, 2 et 3 +1, 2 et 3 +1, 2, 3 +1, 2 ou 3 +1, 2 ou 3 +1, 2 ou 3 +1, 2 et 3 +1, 2 et 3 +1 2 3 \ No newline at end of file From 9236166f72d2d924d4ea46ab39238641b2f69f4c Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Thu, 8 May 2025 01:25:12 +0300 Subject: [PATCH 02/11] Skip test if ICU is older than 67 --- ext/intl/tests/listformatter/listformatter_with_paramaters.phpt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt index a20267f64498e..792baa4095cba 100644 --- a/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt +++ b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt @@ -2,6 +2,8 @@ IntlListFormatter: Test AND, OR and Width parameters --EXTENSIONS-- intl +--SKIPIF-- += 0) die('skip for ICU < 67.0'); ?> --FILE-- Date: Fri, 9 May 2025 00:55:09 +0300 Subject: [PATCH 03/11] Call ZEND_PARSE_PARAMETERS_NONE in getErrorCode and getErrorMessage --- ext/intl/listformatter/listformatter_class.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/intl/listformatter/listformatter_class.c b/ext/intl/listformatter/listformatter_class.c index cf0529399e908..bd153388e043c 100644 --- a/ext/intl/listformatter/listformatter_class.c +++ b/ext/intl/listformatter/listformatter_class.c @@ -186,6 +186,8 @@ PHP_METHOD(IntlListFormatter, format) /* {{{ listformatter_getErrorCode */ PHP_METHOD(IntlListFormatter, getErrorCode) { + ZEND_PARSE_PARAMETERS_NONE(); + ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); UErrorCode status = intl_error_get_code(LISTFORMATTER_ERROR_P(obj)); @@ -197,6 +199,8 @@ PHP_METHOD(IntlListFormatter, getErrorCode) /* {{{ listformatter_getErrorMessage */ PHP_METHOD(IntlListFormatter, getErrorMessage) { + ZEND_PARSE_PARAMETERS_NONE(); + ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); zend_string *message = intl_error_get_message(LISTFORMATTER_ERROR_P(obj)); From a2dd8e9c1c1dbdb71fe19a89611a6e6afcbcad9e Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Fri, 9 May 2025 01:04:10 +0300 Subject: [PATCH 04/11] Make IntlListFormatter final, not serializable and use strict properties --- ext/intl/listformatter/listformatter.stub.php | 5 +++-- ext/intl/listformatter/listformatter_arginfo.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ext/intl/listformatter/listformatter.stub.php b/ext/intl/listformatter/listformatter.stub.php index e5b7815307c03..10a7491156bf5 100644 --- a/ext/intl/listformatter/listformatter.stub.php +++ b/ext/intl/listformatter/listformatter.stub.php @@ -2,8 +2,9 @@ /** @generate-class-entries */ - -class IntlListFormatter { +/** @not-serializable */ +/** @strict-properties */ +final class IntlListFormatter { /** @cvalue ULISTFMT_TYPE_OR */ public const int TYPE_OR = UNKNOWN; diff --git a/ext/intl/listformatter/listformatter_arginfo.h b/ext/intl/listformatter/listformatter_arginfo.h index aaef19b113a73..a66951076b4b8 100644 --- a/ext/intl/listformatter/listformatter_arginfo.h +++ b/ext/intl/listformatter/listformatter_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f76592ef6796059904d6b23b194d789d506823d2 */ + * Stub hash: e4296eb4864ae04804515cf597878e3efb4660ca */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlListFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 0) @@ -35,7 +35,7 @@ static zend_class_entry *register_class_IntlListFormatter(void) zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "IntlListFormatter", class_IntlListFormatter_methods); - class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); zval const_TYPE_OR_value; ZVAL_LONG(&const_TYPE_OR_value, ULISTFMT_TYPE_OR); From e31bfe40fda9554041ec449fc162bb6b48ecae83 Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Sat, 10 May 2025 01:17:36 +0300 Subject: [PATCH 05/11] Added more validation for parameters and fixed coding style --- ext/intl/listformatter/listformatter.stub.php | 28 +++--------- .../listformatter/listformatter_arginfo.h | 2 +- ext/intl/listformatter/listformatter_class.c | 43 +++++++++++++------ .../listformatter/listformatter_error.phpt | 13 +++--- .../listformatter_with_paramaters.phpt | 2 +- .../listformatter_with_parameters_error.phpt | 25 +++++++++++ 6 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 ext/intl/tests/listformatter/listformatter_with_parameters_error.phpt diff --git a/ext/intl/listformatter/listformatter.stub.php b/ext/intl/listformatter/listformatter.stub.php index 10a7491156bf5..28a37f3c5bf0f 100644 --- a/ext/intl/listformatter/listformatter.stub.php +++ b/ext/intl/listformatter/listformatter.stub.php @@ -2,14 +2,16 @@ /** @generate-class-entries */ -/** @not-serializable */ -/** @strict-properties */ +/** + * @not-serializable + * @strict-properties + */ final class IntlListFormatter { - /** @cvalue ULISTFMT_TYPE_OR */ + /** @cvalue ULISTFMT_TYPE_OR */ public const int TYPE_OR = UNKNOWN; - /** @cvalue ULISTFMT_TYPE_UNITS */ + /** @cvalue ULISTFMT_TYPE_UNITS */ public const int TYPE_UNITS = UNKNOWN; /** @cvalue ULISTFMT_TYPE_AND */ @@ -24,27 +26,11 @@ final class IntlListFormatter { /** @cvalue ULISTFMT_WIDTH_NARROW */ public const int WIDTH_NARROW = UNKNOWN; - /** - * @param string $locale - * @param int $type - * @param int $width - */ public function __construct(string $locale, int $type = IntlListFormatter::TYPE_AND, int $width = IntlListFormatter::WIDTH_WIDE) {} - /** - * @param array $strings - * - * @return string|false - */ public function format(array $strings): string|false {} - /** - * @return int - */ public function getErrorCode(): int {} - /** - * @return string - */ public function getErrorMessage(): string {} -} \ No newline at end of file +} diff --git a/ext/intl/listformatter/listformatter_arginfo.h b/ext/intl/listformatter/listformatter_arginfo.h index a66951076b4b8..954edbeee3ede 100644 --- a/ext/intl/listformatter/listformatter_arginfo.h +++ b/ext/intl/listformatter/listformatter_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e4296eb4864ae04804515cf597878e3efb4660ca */ + * Stub hash: a5cf2e1490a5fb3090cbf5cff8a0d890050288a9 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlListFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 0) diff --git a/ext/intl/listformatter/listformatter_class.c b/ext/intl/listformatter/listformatter_class.c index bd153388e043c..853f6358dccab 100644 --- a/ext/intl/listformatter/listformatter_class.c +++ b/ext/intl/listformatter/listformatter_class.c @@ -19,7 +19,6 @@ #include "listformatter_class.h" #include "intl_convert.h" - static zend_object_handlers listformatter_handlers; /* {{{ listformatter_free_obj */ @@ -48,26 +47,45 @@ static zend_object *listformatter_create_object(zend_class_entry *class_type) PHP_METHOD(IntlListFormatter, __construct) { ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); - zend_string *locale; + char* locale; + size_t locale_len = 0; zend_long type = ULISTFMT_TYPE_AND; zend_long width = ULISTFMT_WIDTH_WIDE; ZEND_PARSE_PARAMETERS_START(1, 3) - Z_PARAM_STR(locale) + Z_PARAM_STRING(locale, locale_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(type) Z_PARAM_LONG(width) ZEND_PARSE_PARAMETERS_END(); - if (strlen(uloc_getISO3Language(ZSTR_VAL(locale))) == 0) { - zend_argument_value_error(1, "\"%s\" is invalid", ZSTR_VAL(locale)); - RETURN_THROWS(); - } + if(locale_len == 0) { + locale = (char *)intl_locale_get_default(); + } + + if (strlen(uloc_getISO3Language(locale)) == 0) { + zend_argument_value_error(1, "\"%s\" is invalid", locale); + RETURN_THROWS(); + } + + if (locale_len > INTL_MAX_LOCALE_LEN) { + zend_argument_value_error(1, "Locale string too long, should be no longer than %d characters", INTL_MAX_LOCALE_LEN); + RETURN_THROWS(); + } UErrorCode status = U_ZERO_ERROR; - if (U_ICU_VERSION_MAJOR_NUM >= 67) { + #if U_ICU_VERSION_MAJOR_NUM >= 67 + if (type != ULISTFMT_TYPE_AND && type != ULISTFMT_TYPE_OR && type != ULISTFMT_TYPE_UNITS) { + zend_argument_value_error(2, "must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS"); + RETURN_THROWS(); + } + + if (width != ULISTFMT_WIDTH_WIDE && width != ULISTFMT_WIDTH_SHORT && width != ULISTFMT_WIDTH_NARROW) { + zend_argument_value_error(3, "must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW"); + RETURN_THROWS(); + } - LISTFORMATTER_OBJECT(obj) = ulistfmt_openForType(ZSTR_VAL(locale), type, width, &status); - } else { + LISTFORMATTER_OBJECT(obj) = ulistfmt_openForType(locale, type, width, &status); + #else if (type != ULISTFMT_TYPE_AND) { zend_argument_value_error(2, "ICU 66 and below only support IntlListFormatter::TYPE_AND"); RETURN_THROWS(); @@ -78,8 +96,9 @@ PHP_METHOD(IntlListFormatter, __construct) RETURN_THROWS(); } - LISTFORMATTER_OBJECT(obj) = ulistfmt_open(ZSTR_VAL(locale), &status); - } + LISTFORMATTER_OBJECT(obj) = ulistfmt_open(locale, &status); + #endif + if (U_FAILURE(status)) { intl_error_set(NULL, status, "Constructor failed", 0); zend_throw_exception(IntlException_ce_ptr, "Constructor failed", 0); diff --git a/ext/intl/tests/listformatter/listformatter_error.phpt b/ext/intl/tests/listformatter/listformatter_error.phpt index 36c943bd61dca..f09d5105a8148 100644 --- a/ext/intl/tests/listformatter/listformatter_error.phpt +++ b/ext/intl/tests/listformatter/listformatter_error.phpt @@ -14,15 +14,15 @@ try { echo PHP_EOL; try { - $formatter = new IntlListFormatter('ro', IntlListFormatter::TYPE_AND, 23); -} catch (IntlException $exception) { - echo $exception->getMessage() .PHP_EOL; - echo intl_get_error_code(); + $formatter = new IntlListFormatter('ro_thisiswaytooooooooooooooooooooooooooooooooooooooooooooolongtobevaliditneedstobeatleast157characterstofailthevalidationinthelistformattercodeimplementation', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); +} catch(ValueError $exception) { + echo $exception->getMessage(); } +echo PHP_EOL; + $formatter = new IntlListFormatter('ro', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); -echo PHP_EOL; try { echo $formatter->format([new stdClass()]); } catch(Error $error) { @@ -31,6 +31,5 @@ try { --EXPECT-- IntlListFormatter::__construct(): Argument #1 ($locale) "f" is invalid -Constructor failed -1 +IntlListFormatter::__construct(): Argument #1 ($locale) Locale string too long, should be no longer than 156 characters Object of class stdClass could not be converted to string \ No newline at end of file diff --git a/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt index 792baa4095cba..1243a133cc045 100644 --- a/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt +++ b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt @@ -3,7 +3,7 @@ IntlListFormatter: Test AND, OR and Width parameters --EXTENSIONS-- intl --SKIPIF-- -= 0) die('skip for ICU < 67.0'); ?> + --FILE-- +--FILE-- +getMessage(); +} + +echo PHP_EOL; + +try { + $formatter = new IntlListFormatter('ro', IntlListFormatter::TYPE_AND, 2323232); +} catch(ValueError $exception) { + echo $exception->getMessage(); +} +--EXPECT-- +IntlListFormatter::__construct(): Argument #2 ($type) must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS +IntlListFormatter::__construct(): Argument #3 ($width) must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW From 8524fdcccdbbf078ce0db9d7f352ef66b1967ddc Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Sat, 10 May 2025 01:23:44 +0300 Subject: [PATCH 06/11] Attempt to fix the windows build failure --- ext/intl/config.w32 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index 17b577327bbb9..b281b3c15af28 100644 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -39,6 +39,10 @@ if (PHP_INTL != "no") { formatter_main.c \ formatter_parse.c \ ", "intl"); + ADD_SOURCES(configure_module_dirname + "/listformatter", "\ + listformatter_class.c \ + listformatter_data.c \ + ", "intl"); ADD_SOURCES(configure_module_dirname + "/locale", "\ locale.c \ locale_class.c \ From a096a14b2736c7922547a2e384d7ccca75be1449 Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Sun, 11 May 2025 01:42:08 +0300 Subject: [PATCH 07/11] Simplify the implementation --- ext/intl/config.m4 | 1 - ext/intl/config.w32 | 1 - ext/intl/listformatter/listformatter_class.c | 26 +++-- ext/intl/listformatter/listformatter_class.h | 31 +++--- ext/intl/listformatter/listformatter_data.c | 48 --------- ext/intl/listformatter/listformatter_data.h | 35 ------ .../listformatter/listformatter_basic.phpt | 13 +-- .../listformatter/listformatter_error.phpt | 8 +- .../listformatter_with_paramaters.phpt | 101 +++++------------- 9 files changed, 68 insertions(+), 196 deletions(-) delete mode 100644 ext/intl/listformatter/listformatter_data.c delete mode 100644 ext/intl/listformatter/listformatter_data.h diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 index 0feb0509b7eda..20adc3a4ce3a7 100644 --- a/ext/intl/config.m4 +++ b/ext/intl/config.m4 @@ -40,7 +40,6 @@ if test "$PHP_INTL" != "no"; then locale/locale_methods.c locale/locale.c listformatter/listformatter_class.c - listformatter/listformatter_data.c msgformat/msgformat_attr.c msgformat/msgformat_class.c msgformat/msgformat_data.c diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index b281b3c15af28..b8161865d2540 100644 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -41,7 +41,6 @@ if (PHP_INTL != "no") { ", "intl"); ADD_SOURCES(configure_module_dirname + "/listformatter", "\ listformatter_class.c \ - listformatter_data.c \ ", "intl"); ADD_SOURCES(configure_module_dirname + "/locale", "\ locale.c \ diff --git a/ext/intl/listformatter/listformatter_class.c b/ext/intl/listformatter/listformatter_class.c index 853f6358dccab..10f31f2a46f5f 100644 --- a/ext/intl/listformatter/listformatter_class.c +++ b/ext/intl/listformatter/listformatter_class.c @@ -25,7 +25,13 @@ static zend_object_handlers listformatter_handlers; static void listformatter_free_obj(zend_object *object) { ListFormatter_object *obj = php_intl_listformatter_fetch_object(object); - listformatter_data_free(&obj->lf_data); + + if( obj->lf_data.ulistfmt ) + ulistfmt_close( obj->lf_data.ulistfmt ); + + obj->lf_data.ulistfmt = NULL; + intl_error_reset( &obj->lf_data.error ); + zend_object_std_dtor(&obj->zo); } /* }}} */ @@ -35,7 +41,10 @@ static zend_object *listformatter_create_object(zend_class_entry *class_type) { ListFormatter_object *obj; obj = zend_object_alloc(sizeof(ListFormatter_object), class_type); - listformatter_data_init(&obj->lf_data); + + obj->lf_data.ulistfmt = NULL; + intl_error_reset( &obj->lf_data.error ); + zend_object_std_init(&obj->zo, class_type); object_properties_init(&obj->zo, class_type); obj->zo.handlers = &listformatter_handlers; @@ -62,13 +71,13 @@ PHP_METHOD(IntlListFormatter, __construct) locale = (char *)intl_locale_get_default(); } - if (strlen(uloc_getISO3Language(locale)) == 0) { - zend_argument_value_error(1, "\"%s\" is invalid", locale); + if (locale_len > INTL_MAX_LOCALE_LEN) { + zend_argument_value_error(1, "Locale string too long, should be no longer than %d characters", INTL_MAX_LOCALE_LEN); RETURN_THROWS(); } - if (locale_len > INTL_MAX_LOCALE_LEN) { - zend_argument_value_error(1, "Locale string too long, should be no longer than %d characters", INTL_MAX_LOCALE_LEN); + if (strlen(uloc_getISO3Language(locale)) == 0) { + zend_argument_value_error(1, "\"%s\" is invalid", locale); RETURN_THROWS(); } @@ -145,6 +154,9 @@ PHP_METHOD(IntlListFormatter, format) intl_convert_utf8_to_utf16(&ustr, &ustr_len, ZSTR_VAL(str_val), ZSTR_LEN(str_val), &status); if (U_FAILURE(status)) { + for (uint32_t j = 0; j < i; j++) { + efree((void *)items[j]); + } efree(items); efree(itemLengths); zend_string_release(str_val); @@ -198,7 +210,7 @@ PHP_METHOD(IntlListFormatter, format) RETURN_FALSE; } - RETURN_STR(ret); + RETURN_NEW_STR(ret); } /* }}} */ diff --git a/ext/intl/listformatter/listformatter_class.h b/ext/intl/listformatter/listformatter_class.h index b6183c9f9eff9..4097b29dc631c 100644 --- a/ext/intl/listformatter/listformatter_class.h +++ b/ext/intl/listformatter/listformatter_class.h @@ -20,7 +20,16 @@ #include "intl_common.h" #include "intl_error.h" #include "intl_data.h" -#include "listformatter_data.h" + +#include + +typedef struct { + // error handling + intl_error error; + + // formatter handling + UListFormatter* ulistfmt; +} listformatter_data; typedef struct { listformatter_data lf_data; @@ -32,22 +41,10 @@ static inline ListFormatter_object *php_intl_listformatter_fetch_object(zend_obj } #define Z_INTL_LISTFORMATTER_P(zv) php_intl_listformatter_fetch_object(Z_OBJ_P(zv)) -#define LISTFORMATTER_ERROR(lfo) (lfo)->lf_data.error -#define LISTFORMATTER_ERROR_P(lfo) &(LISTFORMATTER_ERROR(lfo)) - -#define LISTFORMATTER_ERROR_CODE(lfo) INTL_ERROR_CODE(LISTFORMATTER_ERROR(lfo)) -#define LISTFORMATTER_ERROR_CODE_P(lfo) &(INTL_ERROR_CODE(LISTFORMATTER_ERROR(lfo))) - -#define LISTFORMATTER_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(ListFormatter, lfo) -#define LISTFORMATTER_OBJECT(lfo) (lfo)->lf_data.ulistfmt -#define LISTFORMATTER_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(INTL_LISTFORMATTER, lfo) -#define LISTFORMATTER_METHOD_FETCH_OBJECT \ - LISTFORMATTER_METHOD_FETCH_OBJECT_NO_CHECK; \ - if (LISTFORMATTER_OBJECT(lfo) == NULL) \ - { \ - zend_throw_error(NULL, "Found unconstructed ListFormatter"); \ - RETURN_THROWS(); \ - } +#define LISTFORMATTER_ERROR(lfo) (lfo)->lf_data.error +#define LISTFORMATTER_ERROR_P(lfo) &(LISTFORMATTER_ERROR(lfo)) + +#define LISTFORMATTER_OBJECT(lfo) (lfo)->lf_data.ulistfmt void listformatter_register_class( void ); extern zend_class_entry *ListFormatter_ce_ptr; diff --git a/ext/intl/listformatter/listformatter_data.c b/ext/intl/listformatter/listformatter_data.c deleted file mode 100644 index 0cf1f08389db3..0000000000000 --- a/ext/intl/listformatter/listformatter_data.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Bogdan Ungureanu | - +----------------------------------------------------------------------+ -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "listformatter_data.h" - -/* {{{ void listformatter_data_init( listformatter_data* lf_data ) - * Initialize internals of listformatter_data. - */ -void listformatter_data_init( listformatter_data* lf_data ) -{ - if( !lf_data ) - return; - - lf_data->ulistfmt = NULL; - intl_error_reset( &lf_data->error ); -} -/* }}} */ - -/* {{{ void listformatter_data_free( listformatter_data* lf_data ) - * Clean up mem allocated by internals of listformatter_data - */ -void listformatter_data_free( listformatter_data* lf_data ) -{ - if( !lf_data ) - return; - - if( lf_data->ulistfmt ) - ulistfmt_close( lf_data->ulistfmt ); - - lf_data->ulistfmt = NULL; - intl_error_reset( &lf_data->error ); -} -/* }}} */ diff --git a/ext/intl/listformatter/listformatter_data.h b/ext/intl/listformatter/listformatter_data.h deleted file mode 100644 index ae558b79f3306..0000000000000 --- a/ext/intl/listformatter/listformatter_data.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Bogdan Ungureanu | - +----------------------------------------------------------------------+ -*/ - -#ifndef LISTFORMATTER_DATA_H -#define LISTFORMATTER_DATA_H - -#include - -#include - -#include "intl_error.h" - -typedef struct { - // error handling - intl_error error; - - // formatter handling - UListFormatter* ulistfmt; -} listformatter_data; - -void listformatter_data_init( listformatter_data* lf_data ); -void listformatter_data_free( listformatter_data* lf_data ); - -#endif // LISTFORMATTER_DATA_H \ No newline at end of file diff --git a/ext/intl/tests/listformatter/listformatter_basic.phpt b/ext/intl/tests/listformatter/listformatter_basic.phpt index d9130efe86d15..8e2bac77a0d67 100644 --- a/ext/intl/tests/listformatter/listformatter_basic.phpt +++ b/ext/intl/tests/listformatter/listformatter_basic.phpt @@ -8,20 +8,17 @@ intl echo 'EN_US' .PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US'); -echo $formatter->format([1,2,3]); +echo $formatter->format([1,2,3]) . PHP_EOL; -echo PHP_EOL . 'FR' . PHP_EOL; +echo 'FR' . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR'); -echo $formatter->format([1,2,3]); -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; --EXPECT-- EN_US diff --git a/ext/intl/tests/listformatter/listformatter_error.phpt b/ext/intl/tests/listformatter/listformatter_error.phpt index f09d5105a8148..78911b172c792 100644 --- a/ext/intl/tests/listformatter/listformatter_error.phpt +++ b/ext/intl/tests/listformatter/listformatter_error.phpt @@ -8,19 +8,15 @@ intl try { $formatter = new IntlListFormatter('f', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); } catch(ValueError $exception) { - echo $exception->getMessage(); + echo $exception->getMessage() . PHP_EOL; } -echo PHP_EOL; - try { $formatter = new IntlListFormatter('ro_thisiswaytooooooooooooooooooooooooooooooooooooooooooooolongtobevaliditneedstobeatleast157characterstofailthevalidationinthelistformattercodeimplementation', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); } catch(ValueError $exception) { - echo $exception->getMessage(); + echo $exception->getMessage() . PHP_EOL; } -echo PHP_EOL; - $formatter = new IntlListFormatter('ro', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); try { diff --git a/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt index 1243a133cc045..0c56b57cfdc94 100644 --- a/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt +++ b/ext/intl/tests/listformatter/listformatter_with_paramaters.phpt @@ -10,131 +10,86 @@ intl echo 'EN_US' .PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); +echo $formatter->format([1,2,3]) . PHP_EOL; -echo PHP_EOL . 'GB' . PHP_EOL; +echo 'GB' . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('en_GB', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); +echo $formatter->format([1,2,3]) . PHP_EOL; -echo PHP_EOL . 'FR' . PHP_EOL; +echo 'FR' . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT); -echo $formatter->format([1,2,3]); - -echo PHP_EOL; +echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW); echo $formatter->format([1,2,3]); From 7ef138075ea7daf9bf1e3b916c39e5b2f24be85f Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Mon, 12 May 2025 00:36:45 +0300 Subject: [PATCH 08/11] Fix leak and simplify error handling --- ext/intl/listformatter/listformatter_class.c | 29 +++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ext/intl/listformatter/listformatter_class.c b/ext/intl/listformatter/listformatter_class.c index 10f31f2a46f5f..87d58cb31547a 100644 --- a/ext/intl/listformatter/listformatter_class.c +++ b/ext/intl/listformatter/listformatter_class.c @@ -153,20 +153,21 @@ PHP_METHOD(IntlListFormatter, format) UErrorCode status = U_ZERO_ERROR; intl_convert_utf8_to_utf16(&ustr, &ustr_len, ZSTR_VAL(str_val), ZSTR_LEN(str_val), &status); + zend_string_release(str_val); + if (U_FAILURE(status)) { + // We can't use goto cleanup because items and itemLengths are incompletely allocated for (uint32_t j = 0; j < i; j++) { efree((void *)items[j]); } efree(items); efree(itemLengths); - zend_string_release(str_val); intl_error_set(NULL, status, "Failed to convert string to UTF-16", 0); RETURN_FALSE; } items[i] = ustr; itemLengths[i] = ustr_len; - zend_string_release(str_val); i++; } ZEND_HASH_FOREACH_END(); @@ -178,7 +179,8 @@ PHP_METHOD(IntlListFormatter, format) if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) { intl_error_set(NULL, status, "Failed to format list", 0); - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } // Allocate buffer and try again @@ -186,19 +188,13 @@ PHP_METHOD(IntlListFormatter, format) result = (UChar *)emalloc((resultLength + 1) * sizeof(UChar)); ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, result, resultLength, &status); - // Clean up input strings - for (i = 0; i < count; i++) { - efree((void *)items[i]); - } - efree(items); - efree(itemLengths); - if (U_FAILURE(status)) { if (result) { efree(result); } intl_error_set(NULL, status, "Failed to format list", 0); - RETURN_FALSE; + RETVAL_FALSE; + goto cleanup; } // Convert result back to UTF-8 @@ -207,10 +203,17 @@ PHP_METHOD(IntlListFormatter, format) if (!ret) { intl_error_set(NULL, status, "Failed to convert result to UTF-8", 0); - RETURN_FALSE; + RETVAL_FALSE; + } else { + RETVAL_NEW_STR(ret); } - RETURN_NEW_STR(ret); + cleanup: + for (i = 0; i < count; i++) { + efree((void *)items[i]); + } + efree(items); + efree(itemLengths); } /* }}} */ From 685200130bd5a9cad63ae18fa6a81357538184a3 Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Mon, 12 May 2025 01:10:11 +0300 Subject: [PATCH 09/11] Add more tests --- .../listformatter/listformatter_basic.phpt | 34 ++++++++++++++++++- .../listformatter/listformatter_error.phpt | 9 ++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/ext/intl/tests/listformatter/listformatter_basic.phpt b/ext/intl/tests/listformatter/listformatter_basic.phpt index 8e2bac77a0d67..07abb2ac5da0f 100644 --- a/ext/intl/tests/listformatter/listformatter_basic.phpt +++ b/ext/intl/tests/listformatter/listformatter_basic.phpt @@ -12,6 +12,28 @@ echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('EN_US'); echo $formatter->format([1,2,3]) . PHP_EOL; +echo $formatter->format([1.2,2.3,3.4]) . PHP_EOL; + +$item = 'test'; +$item2 = 'test2'; +$item3 = &$item; +$items = [$item, $item2, $item3]; +$items2 = &$items; + +echo $formatter->format($items) . PHP_EOL; +echo $formatter->format($items2) . PHP_EOL; + +echo $formatter->format([null, true, false]) . PHP_EOL; + +$classItem = new class { + public function __toString() { + return 'foo'; + } +}; + +echo $formatter->format([1, $classItem]) . PHP_EOL; + + echo 'FR' . PHP_EOL; $formatter = new IntlListFormatter('FR', IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE); @@ -20,10 +42,20 @@ echo $formatter->format([1,2,3]) . PHP_EOL; $formatter = new IntlListFormatter('FR'); echo $formatter->format([1,2,3]) . PHP_EOL; +// Make it clear that numbers are not converted automatically to the locale. Use NumberFormatter for each value. +echo $formatter->format([1.2,2.3,3.4]) . PHP_EOL; + + --EXPECT-- EN_US 1, 2, and 3 1, 2, and 3 +1.2, 2.3, and 3.4 +test, test2, and test +test, test2, and test +, 1, and +1 and foo FR 1, 2 et 3 -1, 2 et 3 \ No newline at end of file +1, 2 et 3 +1.2, 2.3 et 3.4 \ No newline at end of file diff --git a/ext/intl/tests/listformatter/listformatter_error.phpt b/ext/intl/tests/listformatter/listformatter_error.phpt index 78911b172c792..0709c98313c37 100644 --- a/ext/intl/tests/listformatter/listformatter_error.phpt +++ b/ext/intl/tests/listformatter/listformatter_error.phpt @@ -22,10 +22,17 @@ $formatter = new IntlListFormatter('ro', IntlListFormatter::TYPE_AND, IntlListFo try { echo $formatter->format([new stdClass()]); } catch(Error $error) { - echo $error->getMessage(); + echo $error->getMessage() . PHP_EOL; +} + +try { + echo $formatter->format([1, 2, new stdClass(), 4]); +} catch(Error $error) { + echo $error->getMessage() . PHP_EOL; } --EXPECT-- IntlListFormatter::__construct(): Argument #1 ($locale) "f" is invalid IntlListFormatter::__construct(): Argument #1 ($locale) Locale string too long, should be no longer than 156 characters +Object of class stdClass could not be converted to string Object of class stdClass could not be converted to string \ No newline at end of file From 38515094c4d355d7bccaa450df6e61653a6efd4e Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Tue, 13 May 2025 00:39:12 +0300 Subject: [PATCH 10/11] use safe_emalloc --- ext/intl/listformatter/listformatter_class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/intl/listformatter/listformatter_class.c b/ext/intl/listformatter/listformatter_class.c index 87d58cb31547a..1baf1b348423a 100644 --- a/ext/intl/listformatter/listformatter_class.c +++ b/ext/intl/listformatter/listformatter_class.c @@ -185,7 +185,7 @@ PHP_METHOD(IntlListFormatter, format) // Allocate buffer and try again status = U_ZERO_ERROR; - result = (UChar *)emalloc((resultLength + 1) * sizeof(UChar)); + result = (UChar *)safe_emalloc(resultLength + 1, sizeof(UChar), 0); ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, result, resultLength, &status); if (U_FAILURE(status)) { From 1f64694a597fc2e4084b85c55bc5d5712e7c400e Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Wed, 14 May 2025 00:11:12 +0300 Subject: [PATCH 11/11] Hide unavailable constants for ICU < 67 and remove comments --- ext/intl/listformatter/listformatter.stub.php | 10 ++++++--- .../listformatter/listformatter_arginfo.h | 22 +++++++++++++------ ext/intl/listformatter/listformatter_class.c | 14 ------------ 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/ext/intl/listformatter/listformatter.stub.php b/ext/intl/listformatter/listformatter.stub.php index 28a37f3c5bf0f..b16ad5c270091 100644 --- a/ext/intl/listformatter/listformatter.stub.php +++ b/ext/intl/listformatter/listformatter.stub.php @@ -8,23 +8,27 @@ */ final class IntlListFormatter { + /** @cvalue ULISTFMT_TYPE_AND */ + public const int TYPE_AND = UNKNOWN; + +#if U_ICU_VERSION_MAJOR_NUM >= 67 /** @cvalue ULISTFMT_TYPE_OR */ public const int TYPE_OR = UNKNOWN; /** @cvalue ULISTFMT_TYPE_UNITS */ public const int TYPE_UNITS = UNKNOWN; - - /** @cvalue ULISTFMT_TYPE_AND */ - public const int TYPE_AND = UNKNOWN; +#endif /** @cvalue ULISTFMT_WIDTH_WIDE */ public const int WIDTH_WIDE = UNKNOWN; +#if U_ICU_VERSION_MAJOR_NUM >= 67 /** @cvalue ULISTFMT_WIDTH_SHORT */ public const int WIDTH_SHORT = UNKNOWN; /** @cvalue ULISTFMT_WIDTH_NARROW */ public const int WIDTH_NARROW = UNKNOWN; +#endif public function __construct(string $locale, int $type = IntlListFormatter::TYPE_AND, int $width = IntlListFormatter::WIDTH_WIDE) {} diff --git a/ext/intl/listformatter/listformatter_arginfo.h b/ext/intl/listformatter/listformatter_arginfo.h index 954edbeee3ede..3e18c1154ae76 100644 --- a/ext/intl/listformatter/listformatter_arginfo.h +++ b/ext/intl/listformatter/listformatter_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a5cf2e1490a5fb3090cbf5cff8a0d890050288a9 */ + * Stub hash: f64f4171cfe4f66f976b9350b0a0e22269301ce5 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlListFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 0) @@ -37,41 +37,49 @@ static zend_class_entry *register_class_IntlListFormatter(void) INIT_CLASS_ENTRY(ce, "IntlListFormatter", class_IntlListFormatter_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zval const_TYPE_AND_value; + ZVAL_LONG(&const_TYPE_AND_value, ULISTFMT_TYPE_AND); + zend_string *const_TYPE_AND_name = zend_string_init_interned("TYPE_AND", sizeof("TYPE_AND") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_TYPE_AND_name, &const_TYPE_AND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_TYPE_AND_name); +#if U_ICU_VERSION_MAJOR_NUM >= 67 + zval const_TYPE_OR_value; ZVAL_LONG(&const_TYPE_OR_value, ULISTFMT_TYPE_OR); zend_string *const_TYPE_OR_name = zend_string_init_interned("TYPE_OR", sizeof("TYPE_OR") - 1, 1); zend_declare_typed_class_constant(class_entry, const_TYPE_OR_name, &const_TYPE_OR_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_TYPE_OR_name); +#endif +#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_TYPE_UNITS_value; ZVAL_LONG(&const_TYPE_UNITS_value, ULISTFMT_TYPE_UNITS); zend_string *const_TYPE_UNITS_name = zend_string_init_interned("TYPE_UNITS", sizeof("TYPE_UNITS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_TYPE_UNITS_name, &const_TYPE_UNITS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_TYPE_UNITS_name); - - zval const_TYPE_AND_value; - ZVAL_LONG(&const_TYPE_AND_value, ULISTFMT_TYPE_AND); - zend_string *const_TYPE_AND_name = zend_string_init_interned("TYPE_AND", sizeof("TYPE_AND") - 1, 1); - zend_declare_typed_class_constant(class_entry, const_TYPE_AND_name, &const_TYPE_AND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release(const_TYPE_AND_name); +#endif zval const_WIDTH_WIDE_value; ZVAL_LONG(&const_WIDTH_WIDE_value, ULISTFMT_WIDTH_WIDE); zend_string *const_WIDTH_WIDE_name = zend_string_init_interned("WIDTH_WIDE", sizeof("WIDTH_WIDE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_WIDTH_WIDE_name, &const_WIDTH_WIDE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_WIDTH_WIDE_name); +#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_WIDTH_SHORT_value; ZVAL_LONG(&const_WIDTH_SHORT_value, ULISTFMT_WIDTH_SHORT); zend_string *const_WIDTH_SHORT_name = zend_string_init_interned("WIDTH_SHORT", sizeof("WIDTH_SHORT") - 1, 1); zend_declare_typed_class_constant(class_entry, const_WIDTH_SHORT_name, &const_WIDTH_SHORT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_WIDTH_SHORT_name); +#endif +#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_WIDTH_NARROW_value; ZVAL_LONG(&const_WIDTH_NARROW_value, ULISTFMT_WIDTH_NARROW); zend_string *const_WIDTH_NARROW_name = zend_string_init_interned("WIDTH_NARROW", sizeof("WIDTH_NARROW") - 1, 1); zend_declare_typed_class_constant(class_entry, const_WIDTH_NARROW_name, &const_WIDTH_NARROW_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_WIDTH_NARROW_name); +#endif return class_entry; } diff --git a/ext/intl/listformatter/listformatter_class.c b/ext/intl/listformatter/listformatter_class.c index 1baf1b348423a..a3929c0cb4ddb 100644 --- a/ext/intl/listformatter/listformatter_class.c +++ b/ext/intl/listformatter/listformatter_class.c @@ -21,7 +21,6 @@ static zend_object_handlers listformatter_handlers; -/* {{{ listformatter_free_obj */ static void listformatter_free_obj(zend_object *object) { ListFormatter_object *obj = php_intl_listformatter_fetch_object(object); @@ -34,9 +33,7 @@ static void listformatter_free_obj(zend_object *object) zend_object_std_dtor(&obj->zo); } -/* }}} */ -/* {{{ listformatter_create_object */ static zend_object *listformatter_create_object(zend_class_entry *class_type) { ListFormatter_object *obj; @@ -50,9 +47,7 @@ static zend_object *listformatter_create_object(zend_class_entry *class_type) obj->zo.handlers = &listformatter_handlers; return &obj->zo; } -/* }}} */ -/* {{{ listformatter_create_object */ PHP_METHOD(IntlListFormatter, __construct) { ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); @@ -114,9 +109,7 @@ PHP_METHOD(IntlListFormatter, __construct) RETURN_THROWS(); } } -/* }}} */ -/* {{{ listformatter_format */ PHP_METHOD(IntlListFormatter, format) { ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); @@ -215,9 +208,7 @@ PHP_METHOD(IntlListFormatter, format) efree(items); efree(itemLengths); } -/* }}} */ -/* {{{ listformatter_getErrorCode */ PHP_METHOD(IntlListFormatter, getErrorCode) { ZEND_PARSE_PARAMETERS_NONE(); @@ -228,9 +219,7 @@ PHP_METHOD(IntlListFormatter, getErrorCode) RETURN_LONG(status); } -/* }}} */ -/* {{{ listformatter_getErrorMessage */ PHP_METHOD(IntlListFormatter, getErrorMessage) { ZEND_PARSE_PARAMETERS_NONE(); @@ -240,9 +229,7 @@ PHP_METHOD(IntlListFormatter, getErrorMessage) zend_string *message = intl_error_get_message(LISTFORMATTER_ERROR_P(obj)); RETURN_STR(message); } -/* }}} */ -/* {{{ listformatter_register_class */ void listformatter_register_class(void) { zend_class_entry *class_entry = register_class_IntlListFormatter(); @@ -252,4 +239,3 @@ void listformatter_register_class(void) listformatter_handlers.offset = XtOffsetOf(ListFormatter_object, zo); listformatter_handlers.free_obj = listformatter_free_obj; } -/* }}} */