Skip to content
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

Reflection does not detect optional parameter when they are in an invalid order and PHP does not see this as syntax error. #18127

Open
DirkGerigk opened this issue Mar 21, 2025 · 4 comments

Comments

@DirkGerigk
Copy link

DirkGerigk commented Mar 21, 2025

Description

I report this as bug, but it can also be an feature request.

What is the problem:

A class that defines a optional parameter before an non-optional parameter

  1. That in the first place is not an issue when running the code, if we not using the class or provide both parameter.
  2. It becomes an issue when using named parameter. If only the second parameter 'test' is set, an Exception is thrown.

Side Note:
My IDE PHP Storm normally shows an warning: Optional parameter is provided before required
But this only shows up, when both parameter don't have public
That was the reason why i noticed this hole issue.

Reflection does not detect the optional parameter when there are in the wrong order

As you can see in the provided code, the Reflection detects the parameter 'bar' in Foo as not optional.

  1. This is right, when taken the order of the parameter into account.
  2. This is wrong, when we just look at the single parameter definition.

Conclusion:

Maybe php should throw an syntax error when an wrong parameter order is detected.
Because this is invalid code, but is only detected at run-time under some special conditions.
That Reflection currently shows the result that is does, is maybe fully correct, but is also not so clear.

We are able to do new Foo(...['test'=>'bar']) and that is why i thing php must throw an error when wrong parameter order is detected in the first place.

The following code:

<?php declare(strict_types=1);
class Foo {
    public function __construct(
        public string $bar = 'hallo',
        public string $test,
    )
    {}
}
class Bar {
    public function __construct(
        public string $test,
        public string $bar = 'hallo',
    )
    {}
}
foreach([Foo::class,Bar::class] as $cls){
    foreach(new ReflectionClass($cls)->getConstructor()->getParameters() as $parameter){
        print $cls.' '.$parameter->name.' '.($parameter->isOptional()?'optional':'').PHP_EOL;
    }
}

//no issue
new Foo('Hello','World');

//var_export((array)new Bar(test:'Hello'));
//array ('test' => 'Hello','bar' => 'hallo')

//var_export((array)new Foo(test:'world'));
//PHP Fatal error:  Uncaught ArgumentCountError: Foo::__construct(): Argument #1 ($bar) not passed

Resulted in this output:

Foo bar 
Foo test 
Bar test 
Bar bar optional

But I expected this output instead:

//Some kind of syntax error thrown when optional parameter is before an non-optional parameter

PHP Version

PHP 8.4.5

Operating System

No response

@DirkGerigk DirkGerigk changed the title Reflection does not detect optinal parameter when they are in an invalid order. Reflection does not detect optional parameter when they are in an invalid order. PHP does not see this as syntax error. Mar 21, 2025
@DirkGerigk DirkGerigk changed the title Reflection does not detect optional parameter when they are in an invalid order. PHP does not see this as syntax error. Reflection does not detect optional parameter when they are in an invalid order and PHP does not see this as syntax error. Mar 21, 2025
@iluuu1994
Copy link
Member

iluuu1994 commented Mar 21, 2025

Your example emits this warning:

https://3v4l.org/aMbhv#v8.4.5

Deprecated: Foo::__construct(): Optional parameter $bar declared before required parameter $test is implicitly treated as a required parameter in /in/aMbhv on line 3

This will become an error in PHP 9.0. That's what you're asking for, correct?

@DirkGerigk
Copy link
Author

@iluuu1994 Yes, that is correct.
I'm currently do some prototype coding, seems that the deprecated message is not shown in my console.
Have to check my local php ini setting, normally i work with containers.
Thank you for the quick answer.

Good, that this will be an error in the future.

@iluuu1994
Copy link
Member

iluuu1994 commented Mar 21, 2025

No worries. Thanks for getting back to me. For completeness, the corresponding RFC:

https://wiki.php.net/rfc/deprecate-implicitly-nullable-types

And remove support for implicitly nullable types in PHP 9.

Oops, wrong one. One sec. 🙂

@iluuu1994 iluuu1994 closed this as not planned Won't fix, can't repro, duplicate, stale Mar 21, 2025
@iluuu1994
Copy link
Member

I actually confused this proposal with another one. It looks like this change was made without an RFC:

#5067

Which was discussed here:

https://externals.io/message/108052

It's not completely clear from the discussion whether this should be promoted to an error in 9.0. I think it's best to send a follow-up e-mail and then actually add a TODO on the RFC page so that it is not forgotten.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants