Allow passing methods with arguments to extensionMethod#354
Open
jtojnar wants to merge 1 commit into
Open
Conversation
Since nette@01863f2 introduced `callable(static): mixed` type hint for the `extensionMethod` parameter, it is no longer possible to pass functions with more than one argument to it. This is because argument of type `callable(static): mixed` only has a limited number of subtypes: functions that can be called with the `static` argument, i.e. those functions expecting any superclass of `static`. The functions can also narrow down as they want since the return type since `mixed` is supertype of every type. The functions cannot have any extra arguments since the container would not know what to pass to them. But having fewer arguments is fine since PHP will ignore any extra arguments passed to a function. Formally, the subtyping relation of callables must respect the variance rules: https://www.php.net/manual/en/language.oop5.variance.php If we want to allow wider range of subtypes, we must choose a suitably wide supertype in the type lattice. One option would be just using `mixed` or `callable` but those do not really guide user very well. We want to include at least the `static` argument since that is always passed by `__call`. One option would be using a _bottom_ type (`never`) as the parameter type since it is a subtype of any type – the function with `never` argument can never be called so substituting it with a function that accepts a supertype cannot break any callers, satisfying the contravariance rule. For the return type, we can use a _top_ type (`mixed`) since callers expecting mixed must be able to deal with narrower types so functions returning a subtype cannot break anything either, thus covariance of return type. The main limitation is that we can only have as many arguments as we specify in the type signature as mentioned above. I chose 9 extra arguments since that should be enough for most uses. https://phpstan.org/writing-php-code/phpdoc-types#bottom-type Though, since the function with `never` argument cannot be called because there are no values that can inhabit `never` type, and thus there is nothing to be passed to arguments, we need to cast down the arguments in `__call` to `never` types. This is a valid operation since `never` is a subtype of any type but it is a bit weird. https://phpstan.org/writing-php-code/phpdocs-basics#inline-%40var
Contributor
|
Have you tried |
Contributor
Author
|
Oh, good idea. Unfortunately, that does not seem to work with PHPStan 2.2.5: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Since 01863f2 introduced
callable(static): mixedtype hint for theextensionMethodparameter, it is no longer possible to pass functions with more than one argument to it.This is because argument of type
callable(static): mixedonly has a limited number of subtypes: functions that can be called with thestaticargument, i.e. those functions expecting any superclass ofstatic. The functions can also narrow down as they want since the return type sincemixedis supertype of every type. The functions cannot have any extra arguments since the container would not know what to pass to them. But having fewer arguments is fine since PHP will ignore any extra arguments passed to a function.Formally, the subtyping relation of callables must respect the variance rules.
If we want to allow wider range of subtypes, we must choose a suitably wide supertype in the type lattice. One option would be just using
mixedorcallablebut those do not really guide user very well. We want to include at least thestaticargument since that is always passed by__call.One option would be using a bottom type (
never) as the parameter type since it is a subtype of any type – the function withneverargument can never be called so substituting it with a function that accepts a supertype cannot break any callers, satisfying the contravariance rule. For the return type, we can use a top type (mixed) since callers expecting mixed must be able to deal with narrower types so functions returning a subtype cannot break anything either, thus covariance of return type. The main limitation is that we can only have as many arguments as we specify in the type signature as mentioned above. I chose 9 extra arguments since that should be enough for most uses.Though, since the function with
neverargument cannot be called because there are no values that can inhabitnevertype, and thus there is nothing to be passed to arguments, we need to cast down the arguments in__calltonevertypes. This is a valid operation sinceneveris a subtype of any type but it is a bit weird.