Using PHP 8.4, given the following functions:
function test_array_diff($all, $filtered)
{
return array_diff($all, $filtered);
}
function test_array_udiff($all, $filtered)
{
return array_udiff($all, $filtered, fn($item1, $item2) => $item1 != $item2);
}
function test_in_array($all, $filtered)
{
$diff = [];
foreach ($all as $case) {
if (!in_array($case, $filtered, true)) {
$diff[] = $case;
}
}
return $diff;
}
The following enum:
enum MyEnum
{
case FOO;
case BAR;
}
And those variables:
$all = MyEnum::cases();
$filtered = [MyEnum::BAR];
Why do subsequent calls work as expected:
var_dump(test_array_udiff($all, $filtered));
var_dump(test_in_array($all, $filtered));
But this one throws:
var_dump(test_array_diff($all, $filtered));
Fatal error: Uncaught Error: Object of class MyEnum could not be converted to string
Shouldn’t array_diff()
be able to work "out of the box" with enum arrays in the same way as in_array()
or array_udiff()
?
2
Answers
Although my implementation using
array_udiff()
was bad (it only works for a subset of cases), usingarray_udiff()
to filter elements is a bad idea anyway because of the underlying sorting algorithms applied to the arrays.Nevertheless, I like the RFC's idea, highlighted by @mickmackusa, of being able to use certain array operations on enumeration arrays.
The implementation below using
array_udiff()
with the spaceship operator and the enumeration name works now correctly, but is nevertheless very slow with large arrays.I performed performance tests with the following functions using a hundred-value enumeration class:
foreach
andin_array()
array_reduce()
andin_array()
array_filter()
andin_array()
array_walk()
andin_array()
array_udiff()
On my hardware with PHP 8.4, using the
foreach
loop in conjunction with thein_array()
function gives the fastest results, while using thearray_reduce()
andarray_filter()
functions instead is about ~20% slower, thearray_walk()
function is about ~30% slower, and using thearray_udiff()
function is by far much slower, by over 380%.From the documentation of
array_diff()
:Since enums can’t be converted to strings, this test is not possible.
The equivalent
test_udiff()
would be:Note also that you should use the
<=>
comparison operator. The callback forarray_udiff
should return a negative, positive, or zero value to indicate the relationship between the values, not a boolean.