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()
?
From the documentation of array_diff()
:
Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. That is, when the string representation is the same.
Since enums can't be converted to strings, this test is not possible.
The equivalent test_udiff()
would be:
function test_array_udiff($all, $filtered)
{
return array_udiff($all, $filtered, fn($item1, $item2) => (string)$item1 <=> (string)$item2);
}
Note also that you should use the <=>
comparison operator. The callback for array_udiff
should return a negative, positive, or zero value to indicate the relationship between the values, not a boolean.