Introduction
Function array_is_list() introduced in PHP 8.1 differentiates "array lists" whose indexes are numeric 0..count-1 from associative arrays and arrays having irregular indexes.
Array filtering using array_filter() does work on all arrays, but it exhibits a nuanced behavior on lists leading to subtle bugs. For instance, it preserves keys which can create gaps in sequential indexes. In such cases, a filtered list becomes not a list anymore, which is counterintuitive and can be considered an unintended behavior most of the time.
For example:
$originalList = ['first', '', 'last'];
$filteredList = array_filter($originalList);
var_export(filteredList); // array(0 => 'first', 2 => 'last')
var_export(array_is_list($originalList)); // true
var_export(array_is_list($filteredList)); // false
Furthermore, this can cause unexpected encoding issues:
echo json_encode($originalList); // ["first", "", "last"]
echo json_encode($filteredList); // {"0": "first", "2": "last"}
It's very easy to overlook this behavior. The issue can remain unnoticed on data that contains only trailing items to be filtered out. Even automated tests could be passing, unless they test for the gaps specifically.
Workaround
There is a way to code around this – reset indexes using array_values().
Boilerplate:
$filteredList = array_values(array_filter($originalList));
var_export(filteredList); // array(0 => 'first', 1 => 'last')
var_export(array_is_list($filteredList)); // true
echo json_encode($filteredList); // ["first", "last"]
The workaround is verbose, it hinders readability, and has an unnecessary performance impact (albeit usually negligible) of having to re-build the array with 0..count-1 indexes.
Proposal
The solution is to introduce a new function array_filter_list()
having the same signature as array_filter()
, but working on lists specifically.
$filteredList = array_filter_list($originalList);
The behavior is equivalent to the following:
function array_filter_list(array $array, ?callable $callback = null, int $mode = 0): array
{
if (!array_is_list($array)) {
throw new ValueError('Array list expected');
}
return array_values(array_filter($array, $callback, $mode));
}
Internal implementation should be optimized to avoid rebuilding array indexes from scratch.
Backward Compatibility
The function name array_filter_list()
will be reserved. Any codebase declaring such a function will fail with the following error:
PHP Fatal error: Cannot redeclare array_filter_list()
There are only 4 mentions of this function on GitHub all belonging to the same project Froq! Hassle-free PHP framework which is not mainstream.
Top comments (0)