Update Command::withProgressBar phpdoc to account for arrow functions and non-void return types#58766
Update Command::withProgressBar phpdoc to account for arrow functions and non-void return types#58766billypoke wants to merge 4 commits intolaravel:12.xfrom
Command::withProgressBar phpdoc to account for arrow functions and non-void return types#58766Conversation
|
Something's still not quite right here. I noticed in my other PR #58768 that return types for callables should be wrapped in parentheses. This introduces a new error that I'm still working on - specifically |
|
|
I understand that. There is still an issue here with the type declaration in the PHPDoc. If you implement a progress bar according to the documentation with the current phpdoc or with the updated one, you will see that error. This is not dependent on passing an arrow function vs. an anonymous function. https://phpstan.org/r/f0fc0f19-4037-4b83-bde0-0cff86e397d9 How would you write valid code without throwing an error? |
|
Here's the example with And it works with And here's your arrow function implementation: https://phpstan.org/r/9fb36e9b-9834-4376-977b-ba56e2c27cb5 |
|
In my examples, it's not required that the parameter of the callback be a class, it could be an array or other primitive, such as int. The error remains. I don't care about using or manipulating the bar, just iterating over an array/collection of items and invoking a callback function on each one as described in the documentation. Your examples don't do that. Please show me an example of how you would run a progress bar on anything and have it not throw this error with the PHPDoc as is. To your credit, I really appreciate the additional types being added to the codebase, and I'm not actually convinced that this function can be correctly typed by phpstan with the constraints that generics have. |
It doesn't matter. It's about the type, not the value. Fact is: You produced an invalid example that doesn't reflect the actual problem. What I did is building an example reflecting your problem and applying your fix to the second example, proving that your fix is working. You should be happy that it does.
The param is a progress bar, not an
Thank you 🙂
I don't think, the issue is with the generics here. |
|
The param can be a progress bar, but it can also be the iterable object, as documented in the LARAVEL USAGE DOCUMENTATION FOR WITHPROGRESSBAR, and in the phpdoc you wrote! The first param is either This is literally the most basic, default usage of the function, passing an iterable to https://phpstan.org/r/7a472fc6-7b59-451e-8ae1-9e39fde4614a Tell me how the default usage causes an error please. Look also at the actual function body of What is passed to |
|
Yeah, it can be Yeah, okay, I mixed the progress bar and But there's still an error. We can make the type more precise by making the whole closure a union instead of having two options for every parameter and avoid the error: /**
* Execute a given callback while advancing a progress bar.
*
* @template TKey of array-key
* @template TValue
*
* @param iterable<TKey, TValue>|int $totalSteps
- * @param \Closure(\Symfony\Component\Console\Helper\ProgressBar|TValue, \Symfony\Component\Console\Helper\ProgressBar|null, TKey|null): (mixed|void) $callback
+ * @param \Closure(\Symfony\Component\Console\Helper\ProgressBar): (mixed|void)|\Closure(TValue, \Symfony\Component\Console\Helper\ProgressBar, TKey): (mixed|void) $callback
* @return mixed|void
*/
public function withProgressBar($totalSteps, Closure $callback)Of course, conditional param types would be even better but this seems to be as far as we can get |
|
That should work. I added some more contrived examples to your latest - https://phpstan.org/r/19ae1d8c-f6c3-4df0-bbaf-d8e1f843d39e and they all pass. I'll extend this PR to adopt the dual closure union. |
GrahamCampbell
left a comment
There was a problem hiding this comment.
mixed cannot be included in a union type, because the type simplifies to just mixed once you allow everything.
Interesting, I wasn't aware. Would reducing the return type to only Or would adding another template value Here is a new suggested phpdoc: I added some more examples/tests, including using the return value in the calling function and phpstan correctly identifies that the output array is exactly the input array, or if a non-iterable is passed, that the return value is void - https://phpstan.org/r/8fb06957-9f7c-4488-8e23-3c185810191d |
mixed union return type on withProgressBar $callback paramCommand::withProgressBar phpdoc to account for arrow functions and non-void return types
|
|
|
What benefit does having a concrete type there provide? The return value/type of the callback isn't used or checked anywhere in the function, so there are no constraints on what the return type should be. That's why I called it a no-op in my last comment. It's there to satisfy that the callback should specify its return type, even if it isn't used or checked anywhere |
|
In my opinion, having a PHPDoc triggering static analysis errors when using example from the documentation should be considered a bug. |
In #58565 the return type declaration of many functions was updated, including
Command::withProgressBar. When passing an arrow function as the second argument ($callback), the return value of the callback function is notvoidand will trigger a static analysis warning, as arrow functions in PHP necessarily have a non-voidreturn type.This would pop up if models are being updated in a loop (each
save()returnsbool), or jobs being dispatched (each dispatch returnsPendingDispatchor similar).Adding
mixedas a union type allows callbacks with non-voidreturn types to be passed without failing static analysis. I don't think it's feasible to try and narrow the type any more, but I'm not a static analysis wizard 🧙