-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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
BoundMethod::call() sends parameters in wrong order #22687
Comments
For more information see laravel/framework#22687
I have created a patch and can create pull request if needed. Just waiting for some input. |
Uhm. Let there be input! And there was input! What do you want input on? Submit the PR with the tests, and see if your solutions is approved. |
For more information see laravel#22687
For more information see laravel#22687
For more information see laravel#22687
No, it does not pass the tests. I am currently trying to figure out why this test public function testCallWithCallableArray()
{
$container = new Container;
$stub = new ContainerTestCallStub;
$result = $container->call([$stub, 'work'], ['foo', 'bar']);
$this->assertEquals(['foo', 'bar'], $result);
} expects that this function public function work()
{
return func_get_args();
} returns 2 arguments even though it accepts none. To me this seems like really strange behavior: a function that accepts 0 arguments is passed 2 arguments and is expected to return correct values for those 2 arguments it never accepts. Can you shine some light on why such a test exists and why a function that doesn't accept arguments should be tricked to accept arguments by Laravel framework? |
Php allows you to send an infinite amount of parameters to a function. (Or at least more than those that are declared.) The code can then use func_get_args to retrieve all arguments sent. Perhaps it's easier understood as a variadic function; The test verifies that 1) a callable array |
I was about to use addDependencyForCallParameter function to handle the parameters and dependencies, as this function already handles parameter default values. But this particular function checks the argument count instead of blindly merging dependencies with parameters and then passing this array to the function as arguments. This is why the test doesn't pass, because the arguments given don't match the count of arguments taken. Should such check be removed, or should we never check the argument count at all instead? By the way, should we throw BindingResolutionException if there are parameters that cannot be resolved? Currently BoundMethod does not do so and instead let's PHP do whatever error it does when mandatory arguments are missing. This behvaior is inconsistent with the behavior of Container, which throws BindingResolutionException if an argument is mandatory and cannot be resolved. |
I cannot answer you about specifics on the BoundMethod class, I do not know enough about it. Try #internals on Slack. |
For more information see laravel#22687 We will first resolve the dependencies normal way, but in this commit we will keep track on the order of the parameters. Then we will loop through given parameters if all were not consumed and consume these if we have some unfilled parameters left in our function call. This way we prevent the default value of some parameter being applied to the wrong position. We will need to loop the parameters outside of addDependencyForCallParameter, because calls to this function check for parameter count of the function and send the ReflectionParameter as argument. Because of according to test ContainerTest::testCallWithCallableArary we must give parameters to function even if the function parameter count mismatches, we cannot perform this inside of addDependencyCallParameter.
For more information see laravel#22687 We will first resolve the dependencies normal way, but in this commit we will keep track on the order of the parameters. Then we will loop through given parameters if all were not consumed and consume these if we have some unfilled parameters left in our function call. This way we prevent the default value of some parameter being applied to the wrong position. We will need to loop the parameters outside of addDependencyForCallParameter, because calls to this function check for parameter count of the function and send the ReflectionParameter as argument. Because of according to test ContainerTest::testCallWithCallableArary we must give parameters to function even if the function parameter count mismatches, we cannot perform this inside of addDependencyCallParameter.
For more information see laravel#22687 We will first resolve the dependencies normal way, but in this commit we will keep track on the order of the parameters. Then we will loop through given parameters if all were not consumed and consume these if we have some unfilled parameters left in our function call. This way we prevent the default value of some parameter being applied to the wrong position. We will need to loop the parameters outside of addDependencyForCallParameter, because calls to this function check for parameter count of the function and send the ReflectionParameter as argument. Because of according to test ContainerTest::testCallWithCallableArary we must give parameters to function even if the function parameter count mismatches, we cannot perform this inside of addDependencyCallParameter.
For more information see laravel#22687 We will first resolve the dependencies normal way, but in this commit we will keep track on the order of the parameters. Then we will loop through given parameters if all were not consumed and consume these if we have some unfilled parameters left in our function call. This way we prevent the default value of some parameter being applied to the wrong position. We will need to loop the parameters outside of addDependencyForCallParameter, because calls to this function check for parameter count of the function and send the ReflectionParameter as argument. Because of according to test ContainerTest::testCallWithCallableArary we must give parameters to function even if the function parameter count mismatches, we cannot perform this inside of addDependencyCallParameter.
Closing since the PR was rejected, this usage case isn't documented anywhere. |
* Update BoundMethod.php Bug fix for app()->call('class@method'); fixes: #22687 * Update ContainerTest.php Added tests for app()->call() with default values in the called method * Update ContainerTest.php fixes style-ci issues * fixes the tests Fixes the tests * Fixes the bug caught by tests * more tests to be more sure * Fixes style-CI issue * better tests + typo fix * Passes the most recent test (defaultOnlyC) * More tests covering more cases * Adds more tests Adds more tests * Update ContainerTest.php Fix Style-ci
* Update BoundMethod.php Bug fix for app()->call('class@method'); fixes: laravel/framework#22687 * Update ContainerTest.php Added tests for app()->call() with default values in the called method * Update ContainerTest.php fixes style-ci issues * fixes the tests Fixes the tests * Fixes the bug caught by tests * more tests to be more sure * Fixes style-CI issue * better tests + typo fix * Passes the most recent test (defaultOnlyC) * More tests covering more cases * Adds more tests Adds more tests * Update ContainerTest.php Fix Style-ci
Description:
BoundMethod::call() will send parameters to the function in wrong order in some cases. If a function parameter has a default value set and one precedes it with no default value, the default value from the second parameter will be applied to the first parameter.
Steps To Reproduce:
This will result in output:
So the default value for $type was sent to $url parameter instead.
Explanation:
This is because in BoundMethod on line 119
the results from depedency resolution are merged with no order at all. The dependencies are resolved first and after that the parameters so no order is taken into account.
How to fix:
In function addDepdencyForCallParameter take given parameters into account and fill dependecies in such a way that the order is preserved.
The text was updated successfully, but these errors were encountered: