Skip to content

Commit 5590491

Browse files
committed
ext/intl: Refactor ResourceBundle get and dimension access
1 parent f2e199e commit 5590491

File tree

7 files changed

+142
-54
lines changed

7 files changed

+142
-54
lines changed

ext/intl/php_intl.stub.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,7 @@ function normalizer_get_raw_decomposition(string $string, int $form = Normalizer
543543

544544
function resourcebundle_create(?string $locale, ?string $bundle, bool $fallback = true): ?ResourceBundle {}
545545

546-
/** @param string|int $index */
547-
function resourcebundle_get(ResourceBundle $bundle, $index, bool $fallback = true): mixed {}
546+
function resourcebundle_get(ResourceBundle $bundle, string|int $index, bool $fallback = true): ResourceBundle|array|string|int|null {}
548547

549548
function resourcebundle_count(ResourceBundle $bundle): int {}
550549

ext/intl/php_intl_arginfo.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/intl/resourcebundle/resourcebundle.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,7 @@ void resourcebundle_extract_value( zval *return_value, ResourceBundle_object *so
7171
source->child = NULL;
7272
intl_errors_reset(INTL_DATA_ERROR_P(source));
7373
break;
74-
75-
default:
76-
intl_errors_set(INTL_DATA_ERROR_P(source), U_ILLEGAL_ARGUMENT_ERROR, "Unknown resource type", 0);
77-
RETURN_FALSE;
78-
break;
74+
EMPTY_SWITCH_DEFAULT_CASE();
7975
}
8076
}
8177
/* }}} */

ext/intl/resourcebundle/resourcebundle.stub.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,8 @@ public function __construct(?string $locale, ?string $bundle, bool $fallback = t
1313
*/
1414
public static function create(?string $locale, ?string $bundle, bool $fallback = true): ?ResourceBundle {}
1515

16-
/**
17-
* @param string|int $index
18-
* @tentative-return-type
19-
* @alias resourcebundle_get
20-
*/
21-
public function get($index, bool $fallback = true): mixed {}
16+
/** @tentative-return-type */
17+
public function get(string|int $index, bool $fallback = true): ResourceBundle|array|string|int|null {}
2218

2319
/**
2420
* @tentative-return-type

ext/intl/resourcebundle/resourcebundle_arginfo.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/intl/resourcebundle/resourcebundle_class.c

Lines changed: 75 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -168,84 +168,126 @@ PHP_FUNCTION( resourcebundle_create )
168168
/* }}} */
169169

170170
/* {{{ resourcebundle_array_fetch */
171-
static void resourcebundle_array_fetch(zend_object *object, zval *offset, zval *return_value, int fallback)
171+
static zval *resource_bundle_array_fetch(
172+
zend_object *object, zend_string *offset_str, zend_long offset_int,
173+
zval *return_value, bool fallback, uint32_t offset_arg_num)
172174
{
173-
int32_t meindex = 0;
174-
char * mekey = NULL;
175-
bool is_numeric = 0;
176-
char *pbuf;
175+
int32_t index = 0;
176+
char *key = NULL;
177+
bool is_numeric = offset_str == NULL;
178+
char *pbuf;
177179
ResourceBundle_object *rb;
178180

179181
rb = php_intl_resourcebundle_fetch_object(object);
180182
intl_error_reset(NULL);
181183
intl_error_reset(INTL_DATA_ERROR_P(rb));
182184

183-
if(Z_TYPE_P(offset) == IS_LONG) {
184-
is_numeric = 1;
185-
meindex = (int32_t)Z_LVAL_P(offset);
186-
rb->child = ures_getByIndex( rb->me, meindex, rb->child, &INTL_DATA_ERROR_CODE(rb) );
187-
} else if(Z_TYPE_P(offset) == IS_STRING) {
188-
mekey = Z_STRVAL_P(offset);
189-
rb->child = ures_getByKey(rb->me, mekey, rb->child, &INTL_DATA_ERROR_CODE(rb) );
185+
if (offset_str) {
186+
// TODO Check is not empty?
187+
key = ZSTR_VAL(offset_str);
188+
rb->child = ures_getByKey(rb->me, key, rb->child, &INTL_DATA_ERROR_CODE(rb) );
190189
} else {
191-
intl_errors_set(INTL_DATA_ERROR_P(rb), U_ILLEGAL_ARGUMENT_ERROR,
192-
"resourcebundle_get: index should be integer or string", 0);
193-
RETURN_NULL();
190+
if (UNEXPECTED(offset_int < (zend_long)INT32_MIN || offset_int > (zend_long)INT32_MAX)) {
191+
if (offset_arg_num) {
192+
zend_argument_value_error(offset_arg_num, "index must be between %d and %d", INT32_MIN, INT32_MAX);
193+
} else {
194+
zend_value_error("Index must be between %d and %d", INT32_MIN, INT32_MAX);
195+
}
196+
return NULL;
197+
}
198+
index = (int32_t)offset_int;
199+
rb->child = ures_getByIndex(rb->me, index, rb->child, &INTL_DATA_ERROR_CODE(rb));
194200
}
195201

196202
intl_error_set_code( NULL, INTL_DATA_ERROR_CODE(rb) );
197203
if (U_FAILURE(INTL_DATA_ERROR_CODE(rb))) {
198204
if (is_numeric) {
199-
spprintf( &pbuf, 0, "Cannot load resource element %d", meindex );
205+
spprintf( &pbuf, 0, "Cannot load resource element %d", index );
200206
} else {
201-
spprintf( &pbuf, 0, "Cannot load resource element '%s'", mekey );
207+
spprintf( &pbuf, 0, "Cannot load resource element '%s'", key );
202208
}
203209
intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 );
204210
efree(pbuf);
205-
RETURN_NULL();
211+
RETVAL_NULL();
212+
return return_value;
206213
}
207214

208215
if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING || INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
209216
UErrorCode icuerror;
210217
const char * locale = ures_getLocaleByType( rb->me, ULOC_ACTUAL_LOCALE, &icuerror );
211218
if (is_numeric) {
212-
spprintf( &pbuf, 0, "Cannot load element %d without fallback from to %s", meindex, locale );
219+
spprintf(&pbuf, 0, "Cannot load element %d without fallback from to %s", index, locale);
213220
} else {
214-
spprintf( &pbuf, 0, "Cannot load element '%s' without fallback from to %s", mekey, locale );
221+
spprintf(&pbuf, 0, "Cannot load element '%s' without fallback from to %s", key, locale);
215222
}
216-
intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 );
223+
intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1);
217224
efree(pbuf);
218-
RETURN_NULL();
225+
RETVAL_NULL();
226+
return return_value;
219227
}
220228

221229
resourcebundle_extract_value( return_value, rb );
230+
return return_value;
222231
}
223232
/* }}} */
224233

225234
/* {{{ resourcebundle_array_get */
226235
zval *resourcebundle_array_get(zend_object *object, zval *offset, int type, zval *rv)
227236
{
228-
if(offset == NULL) {
229-
php_error( E_ERROR, "Cannot apply [] to ResourceBundle object" );
237+
if (offset == NULL) {
238+
zend_throw_error(NULL, "Cannot apply [] to ResourceBundle object");
239+
return NULL;
240+
}
241+
242+
if (Z_TYPE_P(offset) == IS_LONG) {
243+
return resource_bundle_array_fetch(object, /* offset_str */ NULL, Z_LVAL_P(offset), rv, /* fallback */ true, /* arg_num */ 0);
244+
} else if (Z_TYPE_P(offset) == IS_STRING) {
245+
return resource_bundle_array_fetch(object, Z_STR_P(offset), /* offset_int */ 0, rv, /* fallback */ true, /* arg_num */ 0);
246+
} else {
247+
zend_illegal_container_offset(object->ce->name, offset, type);
248+
return NULL;
230249
}
231-
ZVAL_NULL(rv);
232-
resourcebundle_array_fetch(object, offset, rv, 1);
233-
return rv;
234250
}
235251
/* }}} */
236252

237253
/* {{{ Get resource identified by numerical index or key name. */
238254
PHP_FUNCTION( resourcebundle_get )
239255
{
240-
bool fallback = 1;
241-
zval * offset;
242-
zval * object;
243-
244-
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz|b", &object, ResourceBundle_ce_ptr, &offset, &fallback ) == FAILURE) {
256+
bool fallback = true;
257+
zend_object *resource_bundle = NULL;
258+
zend_string *offset_str = NULL;
259+
zend_long offset_long = 0;
260+
261+
ZEND_PARSE_PARAMETERS_START(2, 3)
262+
Z_PARAM_OBJ_OF_CLASS(resource_bundle, ResourceBundle_ce_ptr)
263+
Z_PARAM_STR_OR_LONG(offset_str, offset_long)
264+
Z_PARAM_OPTIONAL
265+
Z_PARAM_BOOL(fallback)
266+
ZEND_PARSE_PARAMETERS_END();
267+
268+
zval *retval = resource_bundle_array_fetch(resource_bundle, offset_str, offset_long, return_value, fallback, /* arg_num */ 2);
269+
if (!retval) {
245270
RETURN_THROWS();
246271
}
272+
}
273+
/* }}} */
247274

248-
resourcebundle_array_fetch(Z_OBJ_P(object), offset, return_value, fallback);
275+
PHP_METHOD(ResourceBundle , get)
276+
{
277+
bool fallback = true;
278+
zend_string *offset_str = NULL;
279+
zend_long offset_long = 0;
280+
281+
ZEND_PARSE_PARAMETERS_START(1, 2)
282+
Z_PARAM_STR_OR_LONG(offset_str, offset_long)
283+
Z_PARAM_OPTIONAL
284+
Z_PARAM_BOOL(fallback)
285+
ZEND_PARSE_PARAMETERS_END();
286+
287+
zval *retval = resource_bundle_array_fetch(Z_OBJ_P(ZEND_THIS), offset_str, offset_long, return_value, fallback, /* arg_num */ 1);
288+
if (!retval) {
289+
RETURN_THROWS();
290+
}
249291
}
250292
/* }}} */
251293

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--TEST--
2+
Test ResourceBundle errors with []
3+
--EXTENSIONS--
4+
intl
5+
--FILE--
6+
<?php
7+
include "resourcebundle.inc";
8+
9+
// fall back
10+
$r = new ResourceBundle( 'en_US', BUNDLE );
11+
12+
try {
13+
$ref = &$r[];
14+
} catch (\Throwable $e) {
15+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
16+
}
17+
try {
18+
var_dump(isset($r['non-existent']));
19+
} catch (\Throwable $e) {
20+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
21+
}
22+
try {
23+
var_dump($r['non-existent'] ?? "default");
24+
} catch (\Throwable $e) {
25+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
26+
}
27+
try {
28+
var_dump($r[12.5]);
29+
} catch (\Throwable $e) {
30+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
31+
}
32+
try {
33+
var_dump($r[new stdClass()]);
34+
} catch (\Throwable $e) {
35+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
36+
}
37+
try {
38+
/* This can only happen on 64bit */
39+
if (PHP_INT_SIZE > 4) {
40+
var_dump($r[0xFFFFFFFFF]);
41+
} else {
42+
echo 'ValueError: Index must be between -2147483648 and 2147483647', PHP_EOL;
43+
}
44+
} catch (\Throwable $e) {
45+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
46+
}
47+
48+
?>
49+
--EXPECT--
50+
Error: Cannot apply [] to ResourceBundle object
51+
Error: Cannot use object of type ResourceBundle as array
52+
string(7) "default"
53+
TypeError: Cannot access offset of type float on ResourceBundle
54+
TypeError: Cannot access offset of type stdClass on ResourceBundle
55+
ValueError: Index must be between -2147483648 and 2147483647

0 commit comments

Comments
 (0)