Hi @giuseppe.mazzapica, thank you for sharing your thoughts on this. You bring up some good points, though unfortunately I disagree with nearly all.
As the title of the issue seems to leave the impression that these functions should support full type declarations as supported by PHP, I'm going to change the _typesafe
in the suggested function names to _single_type
.
Let's step through the points you bring up one by one:
Regarding null
Regarding null
there are two cases: the first is that null is the value to be filtered, the second is that null is the value returned by the filters. In the first case, there's basically nothing to do, passing null to apply_filters_typesafe would equal to apply_filters. In the second case, null could be acceptable by the caller.
null
should never be acceptable. As stated before, passing null
as the original value, would mean that running the filters is useless as null
would be the only acceptable outcome.
Regarding filter functions returning null
, that is also not acceptable as it breaks the principle of this function being typesafe. Filters should always return a value and in the case of filters called via these functions, a value of the same type as originally received, so null
would never be an acceptable return.
You are basically suggesting to support "nullable types" in this function. This goes against the principle of one type and one type only and would significantly reduce the advantages of having these functions in the first place.
Regarding callable
I can't think of a single reason for a callable being filterable. To be honest, that just sounds like a security issue waiting to be exploited, which I don't think is a good case to support.
If people still want to do so, let them use apply_filters()
, but I'd really wouldn't want to support it in a function with safe
in the function name.
Regarding iterable
and countable
These I'd need to have a think about, but I'm leaning against a "no", if for no other reason than that it would still require the code in the callback functions hooked into the "typesafe" filter to allow for several different types and several different way to add or remove something from the iterable/countable.
Again, that situation can be handled by using apply_filters()
.
Regarding number
and numeric
First of all, this violates the single type principle again. Second of all, too few people actually understand that is_numeric()
will also accept NAN
, INF
, '1e1'
(floats in exponent annotation), ' 1'
and more.
Also see: https://phpcheatsheets.com/test/numeric_tests/
Supporting number
/numeric
would also negate some of the advantages regarding PHP 8, which introduces "saner numeric comparisons" and "saner numeric strings".
In other words, the behaviour of whatever is passed through would become unpredicatable PHP cross-version, which goes against the whole point of these new functions and would make identifying the callbacks doing it wrong again more difficult.
Regarding mixed
No. Just plain no. Use apply_filters()
, that's the behaviour you expect there. Just like union types, mixed
should not be supported by this function.
I tried to avoid adding an extra argument to make switching existing calls from apply_filters()
to the new functions as easy as possible, but I can see your point about objects.
If we'd go that way, we would basically need to have a "type" key and an "instanceof" key. If "instanceof" is set, "type" would not need to be set, though setting it to object
would be acceptable.
But then, why have two array keys ? We know what the supported basic types are and if whatever is passed (as a string) is not one of the basic types, doing an instanceof
could be done automatically.
Also, and again if we'd go the way of adding a "type" argument, then I'd advocate for the original value being passed to apply_filters_single_type()
to also be evaluated for validity before any callback functions are called, a doing it wrong being thrown if it is not of the expected type and the function short circuiting (not calling any callbacks) if the wrong type was passed.
This function should never fallback to calling apply_filters()
as in that case, it negates the whole point of having this function in place, as callbacks would still not be able to trust the input received from via "typesafe" hooks.
plugin.php can't have external dependencies, so before doing any _doing_it_wrong it is necessary to check that function is defined.
Good point :+1:
// Objects are passed by ref, clone to return original unchanged in case of errors.
Good point, this should definitely be taken into account.