RFC idea: array_*(Enum)

php.internals

Robert Landers

3 years ago
Hello, internals, Currently, this is an Error: $allowedRoles = [Role::Admin]; $hasRoles = [Role::User, Role::Admin]; if(!empty(array_intersect($allowedRoles, $hasRoles))) doSomething(); This is an error because enums cannot be cast to a string (and trying to make them stringable is not allowed) and many array functions expect something stringable. To work around this limitation, the above example must be rewritten like this: array_uintersect($allowedRles, $hasRoles, fn($l, $r) => $l === $r ? 0 : 1)); I'd like to propose an RFC that allows array functions to accept stringable values and enum values. Any other values (like general objects) would be out of scope. I foresee someone bringing up how the natural order of an enum would be determined. The order will be determined via the same order as Enum::cases() outputs, independent of their backed value (e.g., lexicographical order as defined in the code), thus the order of enum Alpha : int { case B = 1; case A = 0; } would be [ Alpha::B, Alpha::A ]. This is what happens when calling sort([Alpha::A, Alpha::B]) currently, so I hope this won't be an issue. Some example functions that would be impacted by this RFC (I still haven't dug into all the array functions yet): - array_intersect - array_diff - array_unique? (works with SORT_REGULAR, so this might need discussion/exemption) If this has been proposed before, I apologize, as I did search for something like this before proposing it. Robert Landers Software Engineer Utrecht NL

mickmackusa

3 years ago
On Thursday, February 23, 2023, Robert Landers <landers.robert@gmail.com> wrote:
> Hello, internals, > > Currently, this is an Error: > > $allowedRoles = [Role::Admin]; > $hasRoles = [Role::User, Role::Admin]; > > if(!empty(array_intersect($allowedRoles, $hasRoles))) doSomething(); > > This is an error because enums cannot be cast to a string (and trying > to make them stringable is not allowed) and many array functions > expect something stringable. To work around this limitation, the above > example must be rewritten like this: > > array_uintersect($allowedRles, $hasRoles, fn($l, $r) => $l === $r ? 0 : > 1)); > > Robert Landers > Software Engineer > Utrecht NL >
---- ...I'd like to add as an aside that: if(!empty(array_intersect($allowedRoles, $hasRoles))) is more simply written as if (array_intersect($allowedRoles, $hasRoles))
-- And for anyone unfamiliar with array_udiff_ and array_uintersect_ functions: 1. The two variables in their callback function signature do not relate by position to the input arrays. This is why it is common to use $a and $b (as is common when calling usort()). In other words, the first input array's data may occur as the first parameter in the callback or the second parameter (like wise with subsequent input arrays). 2. The return value from these functions is expected to be an integer from the result of a three-way comparison -- not the int value of a binary evaluation. Most simply, make a habit of implementing the spaceship operator (<=>). See "array_uintersect() gives unexpected results when callback only returns 0 or 1" @ https://stackoverflow.com/q/8176881/2943403 Another example: https://stackoverflow.com/a/71049380/2943403 The deep dive: https://stackoverflow.com/a/70817582/2943403 mickmackusa