[wp-trac] [WordPress Trac] #51525: Add new functions apply_filters_typesafe() and apply_filters_ref_array_typesafe()
WordPress Trac
noreply at wordpress.org
Thu Oct 15 05:53:26 UTC 2020
#51525: Add new functions apply_filters_typesafe() and
apply_filters_ref_array_typesafe()
-----------------------------+------------------------------------------
Reporter: jrf | Owner: (none)
Type: feature request | Status: new
Priority: normal | Milestone: 5.6
Component: General | Version: trunk
Severity: normal | Keywords: 2nd-opinion needs-patch php8
Focuses: |
-----------------------------+------------------------------------------
This is a proposal to add two new functions `apply_filters_typesafe()` and
`apply_filters_ref_array_typesafe()`.
== Underlying reasons
PHP 8 is a lot more strict about data types and depending on what is done
with the data will start throwing more notices/warnings, but more
concerning exceptions, which will result in fatal errors (= white screen
of death) when uncaught.
== Problem outline
Now, say you have a filter hook `foo` which passes an integer as its
second argument and expects an integer to be returned.
{{{#!php
<?php
$int = apply_filters( 'foo', $int );
}}}
Also say that there are two functions hooked into this filter, function
`plugin_a()` and function `plugin_b()`.
`apply_filters()` will pass the original integer to `plugin_a()` and
subsequently will pass the returned value from `plugin_a()` as the
parameter to `plugin_b()`.
Now take a situation where `plugin_a()` returns something other than an
integer, while `plugin_b()` rightfully expects to receive an integer and
doesn't do additional type checking (which it shouldn't have to do) and
this results in an error.
**Plugin B will be identified in the error backtrace as the place where
the error occurred, so plugin B will be blamed and get a bad reputation,
while plugin A is actually at fault.**
Code example: https://3v4l.org/uqT9G
== Proposed solution
To combat this situation I propose to add two new functions
`apply_filters_typesafe()` and `apply_filters_ref_array_typesafe()`.
These functions would basically have the same underlying logic as the
existing `apply_filters()` and `apply_filters_ref_array()` functions, with
one big difference:
* At the start of the function, the variable type of the second parameter
(the value being filtered) received is checked and remembered.
* In the loop which calls the hooked in functions, a check is done on the
variable type received back from each function and if it doesn't match the
expected variable type, the previous value is used for the call to the
next hooked-in function and a `__doing_it_wrong()` error is thrown
identifying the function which returned the incorrectly typed variable.
This includes doing this check after the last hooked-in function is
called, before returning the value to the original caller of
`apply_filters_typesafe()`.
For `apply_filters_ref_array()`, this would apply to the first array item
in `$args`.
=== Practical advantages
1. Using these functions will prevent potential fatal errors, diminishing
the impact of these type of developer errors for end-users.
2. The "Doing it wrong" notice will make identifying the
function/plugin/theme which caused the problem a lot easier.
3. Plugins/Themes and WP core using the new functions will be able to
count on the parameter/return type of the call to these new functions and
can write their code based on that, without excessive defensive coding to
defend against the errors made by others.
4. Using these functions will help in the efforts to identify more PHP 8
related incompatibilities, both in WP Core as well as in plugins and
themes.
=== Technical considerations
1. I considered adding a new `$typesafe` parameter to the existing
`apply_filters()` function, but as it can be passed a variable number of
arguments to be passed along to the hooked-in functions, this is not an
option. This doesn't apply to `apply_filters_ref_array()`, but for
consistency I think introducing a new sister-function for both would be
the better choice.
2. I've also considered type juggling an incorrectly type value within a
`try/catch`, using that value to pass on to the next function if the
juggling succeeded and only using the previous value if the juggling did
not succeed, but I think that could cause even more problems, so I'd
rather opt for ignoring the incorrectly typed returned value altogether.
== Future scope
Once these functions are in place, a review should be done of all WP Core
calls to `apply_filters()` and `apply_filters_ref_array()` and where the
filtered value is expected to be a singular type, the function call should
be switched out for a call to one of the new functions.
The WP version in which this review is done will need a good dev-note
about these changes as they ''could'' be considered a BC-break, but then
again, they are only a BC_break for hooked-in functions already ''doing it
wrong'' and likely causing problems already.
== Other
I'm tentatively milestoning this for WP 5.6, even though I realize this is
late in the game, but as this proposal could help with the PHP 8 efforts,
I believe it would be good to address this sooner rather than later.
/cc @omarreiss
--
Ticket URL: <https://core.trac.wordpress.org/ticket/51525>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list