Refactor ReflectionMethod::__construct()

Closes GH-6098
This commit is contained in:
Máté Kocsis 2020-09-09 02:21:51 +02:00
parent f33fd9b7fe
commit a59923befd
No known key found for this signature in database
GPG key ID: FD055E41728BF310
7 changed files with 76 additions and 75 deletions

View file

@ -2976,81 +2976,83 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
/* {{{ Constructor. Throws an Exception in case the given method does not exist */ /* {{{ Constructor. Throws an Exception in case the given method does not exist */
ZEND_METHOD(ReflectionMethod, __construct) ZEND_METHOD(ReflectionMethod, __construct)
{ {
zval *classname; zend_object *arg1_obj;
zval *object, *orig_obj; zend_string *arg1_str;
reflection_object *intern; zend_string *arg2_str = NULL;
char *lcname;
zend_class_entry *ce;
zend_function *mptr;
char *name_str, *tmp;
size_t name_len, tmp_len;
zval ztmp;
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "zs", &classname, &name_str, &name_len) == FAILURE) { zend_object *orig_obj = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) { zend_class_entry *ce = NULL;
zend_string *class_name = NULL;
char *method_name;
size_t method_name_len;
char *lcname;
zval *object;
reflection_object *intern;
zend_function *mptr;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR_OR_OBJ(arg1_str, arg1_obj)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(arg2_str)
ZEND_PARSE_PARAMETERS_END();
if (arg1_obj) {
if (!arg2_str) {
zend_argument_value_error(2, "cannot be null when argument #1 ($objectOrMethod) is an object");
RETURN_THROWS(); RETURN_THROWS();
} }
if ((tmp = strstr(name_str, "::")) == NULL) { orig_obj = arg1_obj;
ce = arg1_obj->ce;
method_name = ZSTR_VAL(arg2_str);
method_name_len = ZSTR_LEN(arg2_str);
} else if (arg2_str) {
class_name = zend_string_copy(arg1_str);
method_name = ZSTR_VAL(arg2_str);
method_name_len = ZSTR_LEN(arg2_str);
} else {
char *tmp;
size_t tmp_len;
char *name = ZSTR_VAL(arg1_str);
if ((tmp = strstr(name, "::")) == NULL) {
zend_argument_error(reflection_exception_ptr, 1, "must be a valid method name"); zend_argument_error(reflection_exception_ptr, 1, "must be a valid method name");
RETURN_THROWS(); RETURN_THROWS();
} }
classname = &ztmp; tmp_len = tmp - name;
tmp_len = tmp - name_str;
ZVAL_STRINGL(classname, name_str, tmp_len); class_name = zend_string_init(name, tmp_len, 0);
name_len = name_len - (tmp_len + 2); method_name = tmp + 2;
name_str = tmp + 2; method_name_len = ZSTR_LEN(arg1_str) - tmp_len - 2;
orig_obj = NULL; }
} else if (Z_TYPE_P(classname) == IS_OBJECT) {
orig_obj = classname; if (class_name) {
} else { if ((ce = zend_lookup_class(class_name)) == NULL) {
orig_obj = NULL; if (!EG(exception)) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_name));
}
zend_string_release(class_name);
RETURN_THROWS();
}
zend_string_release(class_name);
} }
object = ZEND_THIS; object = ZEND_THIS;
intern = Z_REFLECTION_P(object); intern = Z_REFLECTION_P(object);
switch (Z_TYPE_P(classname)) { lcname = zend_str_tolower_dup(method_name, method_name_len);
case IS_STRING:
if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) {
if (!EG(exception)) {
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Class \"%s\" does not exist", Z_STRVAL_P(classname));
}
if (classname == &ztmp) {
zval_ptr_dtor_str(&ztmp);
}
RETURN_THROWS();
}
break;
case IS_OBJECT: if (ce == zend_ce_closure && orig_obj && (method_name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
ce = Z_OBJCE_P(classname);
break;
default:
if (classname == &ztmp) {
zval_ptr_dtor_str(&ztmp);
}
zend_argument_error(reflection_exception_ptr, 1, "must be of type object|string, %s given", zend_zval_type_name(classname));
RETURN_THROWS();
}
if (classname == &ztmp) {
zval_ptr_dtor_str(&ztmp);
}
lcname = zend_str_tolower_dup(name_str, name_len);
if (ce == zend_ce_closure && orig_obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
&& (mptr = zend_get_closure_invoke_method(Z_OBJ_P(orig_obj))) != NULL) && (mptr = zend_get_closure_invoke_method(orig_obj)) != NULL)
{ {
/* do nothing, mptr already set */ /* do nothing, mptr already set */
} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, name_len)) == NULL) { } else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
efree(lcname); efree(lcname);
zend_throw_exception_ex(reflection_exception_ptr, 0, zend_throw_exception_ex(reflection_exception_ptr, 0,
"Method %s::%s() does not exist", ZSTR_VAL(ce->name), name_str); "Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
RETURN_THROWS(); RETURN_THROWS();
} }
efree(lcname); efree(lcname);

View file

@ -147,8 +147,7 @@ final class ReflectionGenerator
class ReflectionMethod extends ReflectionFunctionAbstract class ReflectionMethod extends ReflectionFunctionAbstract
{ {
/** @param object|string $objectOrMethod */ public function __construct(object|string $objectOrMethod, ?string $method = null) {}
public function __construct($objectOrMethod, string $method = UNKNOWN) {}
public function __toString(): string {} public function __toString(): string {}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 1311fc5c498d6f16afb5a18aee2d60e72048174f */ * Stub hash: d698afd338e4bf7c782f0edddfcbe95859eef477 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 0, 1) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0)
@ -101,8 +101,8 @@ ZEND_END_ARG_INFO()
#define arginfo_class_ReflectionGenerator_getExecutingGenerator arginfo_class_ReflectionFunctionAbstract___clone #define arginfo_class_ReflectionGenerator_getExecutingGenerator arginfo_class_ReflectionFunctionAbstract___clone
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionMethod___construct, 0, 0, 1) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionMethod___construct, 0, 0, 1)
ZEND_ARG_INFO(0, objectOrMethod) ZEND_ARG_TYPE_MASK(0, objectOrMethod, MAY_BE_OBJECT|MAY_BE_STRING, NULL)
ZEND_ARG_TYPE_INFO(0, method, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, method, IS_STRING, 1, "null")
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#define arginfo_class_ReflectionMethod___toString arginfo_class_ReflectionFunction___toString #define arginfo_class_ReflectionMethod___toString arginfo_class_ReflectionFunction___toString

View file

@ -34,6 +34,6 @@ string(24) "Class "a" does not exist"
string(23) "Class "" does not exist" string(23) "Class "" does not exist"
string(24) "Class "a" does not exist" string(24) "Class "a" does not exist"
string(23) "Class "" does not exist" string(23) "Class "" does not exist"
string(103) "ReflectionMethod::__construct(): Argument #1 ($objectOrMethod) must be of type object|string, int given" string(24) "Class "1" does not exist"
string(23) "Class "" does not exist" string(23) "Class "" does not exist"
Done Done

View file

@ -8,16 +8,16 @@ Steve Seear <stevseea@php.net>
try { try {
new ReflectionMethod(); new ReflectionMethod();
} catch (TypeError $re) { } catch (ArgumentCountError $re) {
echo "Ok - ".$re->getMessage().PHP_EOL; echo "Ok - ".$re->getMessage().PHP_EOL;
} }
try { try {
new ReflectionMethod('a', 'b', 'c'); new ReflectionMethod('a', 'b', 'c');
} catch (TypeError $re) { } catch (ArgumentCountError $re) {
echo "Ok - ".$re->getMessage().PHP_EOL; echo "Ok - ".$re->getMessage().PHP_EOL;
} }
?> ?>
--EXPECT-- --EXPECT--
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 0 given Ok - ReflectionMethod::__construct() expects at least 1 argument, 0 given
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 3 given Ok - ReflectionMethod::__construct() expects at most 2 arguments, 3 given

View file

@ -75,9 +75,9 @@ Stack trace:
#0 %s ReflectionMethod->__construct('3') #0 %s ReflectionMethod->__construct('3')
#1 {main} #1 {main}
Wrong type of argument (bool, string): Wrong type of argument (bool, string):
ReflectionException: ReflectionMethod::__construct(): Argument #1 ($objectOrMethod) must be of type object|string, bool given in %s:%d ReflectionException: Class "1" does not exist in %s:%d
Stack trace: Stack trace:
#0 %s ReflectionMethod->__construct(true, 'foo') #0 %s ReflectionMethod->__construct('1', 'foo')
#1 {main} #1 {main}
Wrong type of argument (string, bool): Wrong type of argument (string, bool):
ReflectionException: Method TestClass::1() does not exist in %s:%d ReflectionException: Method TestClass::1() does not exist in %s:%d

View file

@ -16,13 +16,13 @@ class TestClass
try { try {
echo "Too few arguments:\n"; echo "Too few arguments:\n";
$methodInfo = new ReflectionMethod(); $methodInfo = new ReflectionMethod();
} catch (TypeError $re) { } catch (ArgumentCountError $re) {
echo "Ok - ".$re->getMessage().PHP_EOL; echo "Ok - ".$re->getMessage().PHP_EOL;
} }
try { try {
echo "\nToo many arguments:\n"; echo "\nToo many arguments:\n";
$methodInfo = new ReflectionMethod("TestClass", "foo", true); $methodInfo = new ReflectionMethod("TestClass", "foo", true);
} catch (TypeError $re) { } catch (ArgumentCountError $re) {
echo "Ok - ".$re->getMessage().PHP_EOL; echo "Ok - ".$re->getMessage().PHP_EOL;
} }
@ -38,7 +38,7 @@ try {
try { try {
//invalid 1st param //invalid 1st param
$methodInfo = new ReflectionMethod([], "foo"); $methodInfo = new ReflectionMethod([], "foo");
} catch (ReflectionException $re) { } catch (TypeError $re) {
echo "Ok - ".$re->getMessage().PHP_EOL; echo "Ok - ".$re->getMessage().PHP_EOL;
} }
@ -52,10 +52,10 @@ try{
?> ?>
--EXPECT-- --EXPECT--
Too few arguments: Too few arguments:
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 0 given Ok - ReflectionMethod::__construct() expects at least 1 argument, 0 given
Too many arguments: Too many arguments:
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 3 given Ok - ReflectionMethod::__construct() expects at most 2 arguments, 3 given
Ok - Class "InvalidClassName" does not exist Ok - Class "InvalidClassName" does not exist
Ok - ReflectionMethod::__construct(): Argument #1 ($objectOrMethod) must be of type object|string, array given Ok - ReflectionMethod::__construct(): Argument #1 ($objectOrMethod) must be of type object|string, array given
Ok - ReflectionMethod::__construct() expects exactly 1 argument, 2 given Ok - ReflectionMethod::__construct(): Argument #2 ($method) must be of type ?string, array given