Skip to content

Commit d6b0c76

Browse files
authored
Zend: handle non-string arguments for ZPP class-string specifier as expected (#23001)
* Zend: add tests for ZPP class-string specifier * Zend: handle non-string arguments for ZPP class-string specifier as expected This doesn't behave like any of the other specifiers, as it doesn't respect strict_types, emit a deprecation for null, or reject arrays
1 parent 7785159 commit d6b0c76

3 files changed

Lines changed: 104 additions & 5 deletions

File tree

Zend/zend_API.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,27 +486,29 @@ ZEND_API ZEND_COLD void zend_class_redeclaration_error(int type, const zend_clas
486486

487487
ZEND_API bool ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **pce, uint32_t num, bool check_null) /* {{{ */
488488
{
489-
zend_class_entry *ce_base = *pce;
489+
const zend_class_entry *ce_base = *pce;
490490

491491
if (check_null && Z_TYPE_P(arg) == IS_NULL) {
492492
*pce = NULL;
493493
return 1;
494494
}
495-
if (!try_convert_to_string(arg)) {
495+
zend_string *class_name;
496+
if (!zend_parse_arg_str(arg, &class_name, check_null, num)) {
496497
*pce = NULL;
498+
zend_wrong_parameter_error(ZPP_ERROR_WRONG_ARG, num, NULL, check_null ? Z_EXPECTED_STRING_OR_NULL : Z_EXPECTED_STRING, arg);
497499
return 0;
498500
}
499501

500-
*pce = zend_lookup_class(Z_STR_P(arg));
502+
*pce = zend_lookup_class(class_name);
501503
if (ce_base) {
502504
if ((!*pce || !instanceof_function(*pce, ce_base))) {
503-
zend_argument_type_error(num, "must be a class name derived from %s, %s given", ZSTR_VAL(ce_base->name), Z_STRVAL_P(arg));
505+
zend_argument_type_error(num, "must be a class name derived from %s, %s given", ZSTR_VAL(ce_base->name), ZSTR_VAL(class_name));
504506
*pce = NULL;
505507
return 0;
506508
}
507509
}
508510
if (!*pce) {
509-
zend_argument_type_error(num, "must be a valid class name, %s given", Z_STRVAL_P(arg));
511+
zend_argument_type_error(num, "must be a valid class name, %s given", ZSTR_VAL(class_name));
510512
return 0;
511513
}
512514
return 1;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
Test class string ZPP specifier
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
declare(strict_types=1);
9+
10+
class S {
11+
public function __toString(): string {
12+
return 'S class';
13+
}
14+
}
15+
16+
$types = [
17+
null,
18+
false,
19+
true,
20+
42,
21+
73.5,
22+
'string',
23+
[],
24+
new stdClass(),
25+
new S(),
26+
STDOUT,
27+
];
28+
29+
foreach ($types as $type) {
30+
/* Use zend_object_init_with_constructor() function as it used Z_PARAM_CLASS */
31+
try {
32+
var_dump(zend_object_init_with_constructor($type));
33+
} catch (Throwable $e) {
34+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
35+
}
36+
}
37+
38+
?>
39+
--EXPECT--
40+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, null given
41+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, false given
42+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, true given
43+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, int given
44+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, float given
45+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, string given
46+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, array given
47+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, stdClass given
48+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, S given
49+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, resource given
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
Test class string ZPP specifier
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
class S {
9+
public function __toString(): string {
10+
return 'S class';
11+
}
12+
}
13+
14+
$types = [
15+
null,
16+
false,
17+
true,
18+
42,
19+
73.5,
20+
'string',
21+
[],
22+
new stdClass(),
23+
new S(),
24+
STDOUT,
25+
];
26+
27+
foreach ($types as $type) {
28+
/* Use zend_object_init_with_constructor() function as it used Z_PARAM_CLASS */
29+
try {
30+
var_dump(zend_object_init_with_constructor($type));
31+
} catch (Throwable $e) {
32+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
33+
}
34+
}
35+
36+
?>
37+
--EXPECTF--
38+
Deprecated: zend_object_init_with_constructor(): Passing null to parameter #1 ($class) of type string is deprecated in %s on line %d
39+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, given
40+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, given
41+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, 1 given
42+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, 42 given
43+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, 73.5 given
44+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, string given
45+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, array given
46+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, stdClass given
47+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be a valid class name, S class given
48+
TypeError: zend_object_init_with_constructor(): Argument #1 ($class) must be of type string, resource given

0 commit comments

Comments
 (0)