Skip to content

Commit a59923b

Browse files
committed
Refactor ReflectionMethod::__construct()
Closes GH-6098
1 parent f33fd9b commit a59923b

7 files changed

+72
-71
lines changed

ext/reflection/php_reflection.c

Lines changed: 55 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2976,81 +2976,83 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
29762976
/* {{{ Constructor. Throws an Exception in case the given method does not exist */
29772977
ZEND_METHOD(ReflectionMethod, __construct)
29782978
{
2979-
zval *classname;
2980-
zval *object, *orig_obj;
2981-
reflection_object *intern;
2979+
zend_object *arg1_obj;
2980+
zend_string *arg1_str;
2981+
zend_string *arg2_str = NULL;
2982+
2983+
zend_object *orig_obj = NULL;
2984+
zend_class_entry *ce = NULL;
2985+
zend_string *class_name = NULL;
2986+
char *method_name;
2987+
size_t method_name_len;
29822988
char *lcname;
2983-
zend_class_entry *ce;
2989+
2990+
zval *object;
2991+
reflection_object *intern;
29842992
zend_function *mptr;
2985-
char *name_str, *tmp;
2986-
size_t name_len, tmp_len;
2987-
zval ztmp;
29882993

2989-
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "zs", &classname, &name_str, &name_len) == FAILURE) {
2990-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
2994+
ZEND_PARSE_PARAMETERS_START(1, 2)
2995+
Z_PARAM_STR_OR_OBJ(arg1_str, arg1_obj)
2996+
Z_PARAM_OPTIONAL
2997+
Z_PARAM_STR_OR_NULL(arg2_str)
2998+
ZEND_PARSE_PARAMETERS_END();
2999+
3000+
if (arg1_obj) {
3001+
if (!arg2_str) {
3002+
zend_argument_value_error(2, "cannot be null when argument #1 ($objectOrMethod) is an object");
29913003
RETURN_THROWS();
29923004
}
29933005

2994-
if ((tmp = strstr(name_str, "::")) == NULL) {
3006+
orig_obj = arg1_obj;
3007+
ce = arg1_obj->ce;
3008+
method_name = ZSTR_VAL(arg2_str);
3009+
method_name_len = ZSTR_LEN(arg2_str);
3010+
} else if (arg2_str) {
3011+
class_name = zend_string_copy(arg1_str);
3012+
method_name = ZSTR_VAL(arg2_str);
3013+
method_name_len = ZSTR_LEN(arg2_str);
3014+
} else {
3015+
char *tmp;
3016+
size_t tmp_len;
3017+
char *name = ZSTR_VAL(arg1_str);
3018+
3019+
if ((tmp = strstr(name, "::")) == NULL) {
29953020
zend_argument_error(reflection_exception_ptr, 1, "must be a valid method name");
29963021
RETURN_THROWS();
29973022
}
2998-
classname = &ztmp;
2999-
tmp_len = tmp - name_str;
3000-
ZVAL_STRINGL(classname, name_str, tmp_len);
3001-
name_len = name_len - (tmp_len + 2);
3002-
name_str = tmp + 2;
3003-
orig_obj = NULL;
3004-
} else if (Z_TYPE_P(classname) == IS_OBJECT) {
3005-
orig_obj = classname;
3006-
} else {
3007-
orig_obj = NULL;
3008-
}
3023+
tmp_len = tmp - name;
30093024

3010-
object = ZEND_THIS;
3011-
intern = Z_REFLECTION_P(object);
3012-
3013-
switch (Z_TYPE_P(classname)) {
3014-
case IS_STRING:
3015-
if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) {
3016-
if (!EG(exception)) {
3017-
zend_throw_exception_ex(reflection_exception_ptr, 0,
3018-
"Class \"%s\" does not exist", Z_STRVAL_P(classname));
3019-
}
3020-
if (classname == &ztmp) {
3021-
zval_ptr_dtor_str(&ztmp);
3022-
}
3023-
RETURN_THROWS();
3024-
}
3025-
break;
3026-
3027-
case IS_OBJECT:
3028-
ce = Z_OBJCE_P(classname);
3029-
break;
3025+
class_name = zend_string_init(name, tmp_len, 0);
3026+
method_name = tmp + 2;
3027+
method_name_len = ZSTR_LEN(arg1_str) - tmp_len - 2;
3028+
}
30303029

3031-
default:
3032-
if (classname == &ztmp) {
3033-
zval_ptr_dtor_str(&ztmp);
3030+
if (class_name) {
3031+
if ((ce = zend_lookup_class(class_name)) == NULL) {
3032+
if (!EG(exception)) {
3033+
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_name));
30343034
}
3035-
zend_argument_error(reflection_exception_ptr, 1, "must be of type object|string, %s given", zend_zval_type_name(classname));
3035+
zend_string_release(class_name);
30363036
RETURN_THROWS();
3037-
}
3037+
}
30383038

3039-
if (classname == &ztmp) {
3040-
zval_ptr_dtor_str(&ztmp);
3039+
zend_string_release(class_name);
30413040
}
30423041

3043-
lcname = zend_str_tolower_dup(name_str, name_len);
3042+
object = ZEND_THIS;
3043+
intern = Z_REFLECTION_P(object);
3044+
3045+
lcname = zend_str_tolower_dup(method_name, method_name_len);
30443046

3045-
if (ce == zend_ce_closure && orig_obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
3047+
if (ce == zend_ce_closure && orig_obj && (method_name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
30463048
&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3047-
&& (mptr = zend_get_closure_invoke_method(Z_OBJ_P(orig_obj))) != NULL)
3049+
&& (mptr = zend_get_closure_invoke_method(orig_obj)) != NULL)
30483050
{
30493051
/* do nothing, mptr already set */
3050-
} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, name_len)) == NULL) {
3052+
} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
30513053
efree(lcname);
30523054
zend_throw_exception_ex(reflection_exception_ptr, 0,
3053-
"Method %s::%s() does not exist", ZSTR_VAL(ce->name), name_str);
3055+
"Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
30543056
RETURN_THROWS();
30553057
}
30563058
efree(lcname);

ext/reflection/php_reflection.stub.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,7 @@ public function getExecutingGenerator() {}
147147

148148
class ReflectionMethod extends ReflectionFunctionAbstract
149149
{
150-
/** @param object|string $objectOrMethod */
151-
public function __construct($objectOrMethod, string $method = UNKNOWN) {}
150+
public function __construct(object|string $objectOrMethod, ?string $method = null) {}
152151

153152
public function __toString(): string {}
154153

ext/reflection/php_reflection_arginfo.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 1311fc5c498d6f16afb5a18aee2d60e72048174f */
2+
* Stub hash: d698afd338e4bf7c782f0edddfcbe95859eef477 */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 0, 1)
55
ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0)
@@ -101,8 +101,8 @@ ZEND_END_ARG_INFO()
101101
#define arginfo_class_ReflectionGenerator_getExecutingGenerator arginfo_class_ReflectionFunctionAbstract___clone
102102

103103
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionMethod___construct, 0, 0, 1)
104-
ZEND_ARG_INFO(0, objectOrMethod)
105-
ZEND_ARG_TYPE_INFO(0, method, IS_STRING, 0)
104+
ZEND_ARG_TYPE_MASK(0, objectOrMethod, MAY_BE_OBJECT|MAY_BE_STRING, NULL)
105+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, method, IS_STRING, 1, "null")
106106
ZEND_END_ARG_INFO()
107107

108108
#define arginfo_class_ReflectionMethod___toString arginfo_class_ReflectionFunction___toString

ext/reflection/tests/008.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ string(24) "Class "a" does not exist"
3434
string(23) "Class "" does not exist"
3535
string(24) "Class "a" does not exist"
3636
string(23) "Class "" does not exist"
37-
string(103) "ReflectionMethod::__construct(): Argument #1 ($objectOrMethod) must be of type object|string, int given"
37+
string(24) "Class "1" does not exist"
3838
string(23) "Class "" does not exist"
3939
Done

ext/reflection/tests/ReflectionMethod_006.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ Steve Seear <stevseea@php.net>
88

99
try {
1010
new ReflectionMethod();
11-
} catch (TypeError $re) {
11+
} catch (ArgumentCountError $re) {
1212
echo "Ok - ".$re->getMessage().PHP_EOL;
1313
}
1414
try {
1515
new ReflectionMethod('a', 'b', 'c');
16-
} catch (TypeError $re) {
16+
} catch (ArgumentCountError $re) {
1717
echo "Ok - ".$re->getMessage().PHP_EOL;
1818
}
1919

2020
?>
2121
--EXPECT--
22-
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 0 given
23-
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 3 given
22+
Ok - ReflectionMethod::__construct() expects at least 1 argument, 0 given
23+
Ok - ReflectionMethod::__construct() expects at most 2 arguments, 3 given

ext/reflection/tests/ReflectionMethod_constructor_error1.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ Stack trace:
7575
#0 %s ReflectionMethod->__construct('3')
7676
#1 {main}
7777
Wrong type of argument (bool, string):
78-
ReflectionException: ReflectionMethod::__construct(): Argument #1 ($objectOrMethod) must be of type object|string, bool given in %s:%d
78+
ReflectionException: Class "1" does not exist in %s:%d
7979
Stack trace:
80-
#0 %s ReflectionMethod->__construct(true, 'foo')
80+
#0 %s ReflectionMethod->__construct('1', 'foo')
8181
#1 {main}
8282
Wrong type of argument (string, bool):
8383
ReflectionException: Method TestClass::1() does not exist in %s:%d

ext/reflection/tests/ReflectionMethod_constructor_error2.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ class TestClass
1616
try {
1717
echo "Too few arguments:\n";
1818
$methodInfo = new ReflectionMethod();
19-
} catch (TypeError $re) {
19+
} catch (ArgumentCountError $re) {
2020
echo "Ok - ".$re->getMessage().PHP_EOL;
2121
}
2222
try {
2323
echo "\nToo many arguments:\n";
2424
$methodInfo = new ReflectionMethod("TestClass", "foo", true);
25-
} catch (TypeError $re) {
25+
} catch (ArgumentCountError $re) {
2626
echo "Ok - ".$re->getMessage().PHP_EOL;
2727
}
2828

@@ -38,7 +38,7 @@ try {
3838
try {
3939
//invalid 1st param
4040
$methodInfo = new ReflectionMethod([], "foo");
41-
} catch (ReflectionException $re) {
41+
} catch (TypeError $re) {
4242
echo "Ok - ".$re->getMessage().PHP_EOL;
4343
}
4444

@@ -52,10 +52,10 @@ try{
5252
?>
5353
--EXPECT--
5454
Too few arguments:
55-
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 0 given
55+
Ok - ReflectionMethod::__construct() expects at least 1 argument, 0 given
5656

5757
Too many arguments:
58-
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 3 given
58+
Ok - ReflectionMethod::__construct() expects at most 2 arguments, 3 given
5959
Ok - Class "InvalidClassName" does not exist
6060
Ok - ReflectionMethod::__construct(): Argument #1 ($objectOrMethod) must be of type object|string, array given
61-
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 2 given
61+
Ok - ReflectionMethod::__construct(): Argument #2 ($method) must be of type ?string, array given

0 commit comments

Comments
 (0)