Skip to content

GH-12371: "internal error" in ReflectionParameter::getDefaultValue on Variable-length argument list #12372

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: PHP-8.1
Choose a base branch
from

Conversation

nielsdos
Copy link
Member

@nielsdos nielsdos commented Oct 6, 2023

When you query if these are optional, they return true, but when you query the default value you get an exception. From the documentation of getDefaultValue() [1] we see that:

If the parameter is not optional a ReflectionException will be thrown.

So that seems to imply it should work with variadics.

The root cause is that we're only checking ZEND_RECV_INIT, and returning NULL in get_default_from_recv() when encountering ZEND_RECV_VARIADIC. Fix it by adding an is_variadic boolean that we can check. We'll also have to change zend_get_default_from_internal_arg_info() to fix the support for internal arguments.

… on Variable-length argument list

When you query if these are optional, they return true, but when you
query the default value you get an exception. From the documentation of
getDefaultValue() [1] we see that:

> If the parameter is not optional a ReflectionException will be thrown.

So that seems to imply it should work with variadics.

The root cause is that we're only checking ZEND_RECV_INIT, and returning
NULL in get_default_from_recv() when encountering ZEND_RECV_VARIADIC.
Fix it by adding an is_variadic boolean that we can check. We'll also
have to change zend_get_default_from_internal_arg_info() to fix the
support for internal arguments.
@divinity76
Copy link
Contributor

divinity76 commented Oct 17, 2023

instead of

	if (!recv || recv->opcode != ZEND_RECV_INIT) {
		*is_variadic = recv && recv->opcode == ZEND_RECV_VARIADIC;
		return NULL;
	}

wouldn't it be better to just

	if (!recv || recv->opcode != ZEND_RECV_INIT) {
		if(recv && recv->opcode == ZEND_RECV_VARIADIC){
			return (whatever RT_CONSTANT(...) would return here when the default is an empty array);
                }
		return NULL;
	}

? then we wouldn't need the extra by-ref argument and no new logic for calling get_default_from_recv~
(* not sure exactly how to implement it, but shouldn't be too hard to figure out if we decide it's worthwhile~)

Copy link
Member

@iluuu1994 iluuu1994 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change makes sense and simplifies things, although I wonder whether that makes isDefaultValueAvailable() useless. Or are there still cases where isOptional returns something other than isDefaultValueAvailable? Nowadays default values are implicitly removed if the parameter is followed by a non-optional parameter (https://3v4l.org/CCXWB). Because of the existence of isDefaultValueAvailable(), I'm also not sure whether this is a bug-fix or an enhancement of the API.

@nielsdos
Copy link
Member Author

I think this change makes sense and simplifies things, although I wonder whether that makes isDefaultValueAvailable() useless. Or are there still cases where isOptional returns something other than isDefaultValueAvailable?

I'm not sure. The expected semantics w.r.t. variadics are not defined in the manual.
If we we define the default value of an argument as "the value you write after the equals sign", then variadics don't have a default value but are still optional. That would however be contradictory with the manual: "If the parameter is not optional a ReflectionException will be thrown.".

I'm also not sure whether this is a bug-fix or an enhancement of the API.

In that case, it may be best to put this into master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
4 participants