Skip to content

Commit 42fad69

Browse files
committed
Support enums in array_unique
Fixes GH-9775
1 parent 0579beb commit 42fad69

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

Zend/tests/gh9775.phpt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
GH-9775: Enum in array_unique()
3+
--FILE--
4+
<?php
5+
6+
enum Test: string
7+
{
8+
case AUTHENTICATED = 'authenticated';
9+
case COURSES_ADMIN = 'courses.admin';
10+
case BUNDLES_ADMIN = 'bundles.admin';
11+
case COURSES_REPORTING_ACCESS = 'courses-reporting.access';
12+
case B2B_DASHBOARD_ACCESS = 'b2b-dashboard.access';
13+
case INSTRUCTORS_ADMIN = 'instructors.admin';
14+
case USERS_ADMIN = 'users.admin';
15+
case COUPONS_ADMIN = 'coupons.admin';
16+
}
17+
18+
$data = [
19+
Test::COURSES_ADMIN,
20+
Test::COURSES_REPORTING_ACCESS,
21+
Test::BUNDLES_ADMIN,
22+
Test::USERS_ADMIN,
23+
Test::B2B_DASHBOARD_ACCESS,
24+
Test::B2B_DASHBOARD_ACCESS,
25+
Test::INSTRUCTORS_ADMIN,
26+
Test::INSTRUCTORS_ADMIN,
27+
Test::COUPONS_ADMIN,
28+
Test::AUTHENTICATED,
29+
];
30+
31+
$data = array_unique($data, flags: SORT_REGULAR);
32+
33+
var_dump($data);
34+
35+
?>
36+
--EXPECT--
37+
array(8) {
38+
[0]=>
39+
enum(Test::COURSES_ADMIN)
40+
[1]=>
41+
enum(Test::COURSES_REPORTING_ACCESS)
42+
[2]=>
43+
enum(Test::BUNDLES_ADMIN)
44+
[3]=>
45+
enum(Test::USERS_ADMIN)
46+
[4]=>
47+
enum(Test::B2B_DASHBOARD_ACCESS)
48+
[6]=>
49+
enum(Test::INSTRUCTORS_ADMIN)
50+
[8]=>
51+
enum(Test::COUPONS_ADMIN)
52+
[9]=>
53+
enum(Test::AUTHENTICATED)
54+
}

ext/standard/array.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,24 @@ static zend_always_inline int php_array_key_compare_string_locale_unstable_i(Buc
345345

346346
static zend_always_inline int php_array_data_compare_unstable_i(Bucket *f, Bucket *s) /* {{{ */
347347
{
348-
return zend_compare(&f->val, &s->val);
348+
int result = zend_compare(&f->val, &s->val);
349+
// Special handling for enums
350+
if (result == ZEND_UNCOMPARABLE) {
351+
zval *rhs = &s->val;
352+
if (UNEXPECTED(Z_TYPE_P(rhs) == IS_OBJECT && (Z_OBJCE_P(rhs)->ce_flags & ZEND_ACC_ENUM))) {
353+
zval *lhs = &f->val;
354+
if (Z_TYPE_P(lhs) == IS_OBJECT && (Z_OBJCE_P(lhs)->ce_flags & ZEND_ACC_ENUM)) {
355+
// Order doesn't matter, we just need to group the same enum values
356+
uintptr_t lhs_uintptr = (uintptr_t)Z_OBJ_P(lhs);
357+
uintptr_t rhs_uintptr = (uintptr_t)Z_OBJ_P(rhs);
358+
return lhs_uintptr == rhs_uintptr ? 0 : (lhs_uintptr < rhs_uintptr ? -1 : 1);
359+
} else {
360+
// Shift enums to the end of the array
361+
return -1;
362+
}
363+
}
364+
}
365+
return result;
349366
}
350367
/* }}} */
351368

0 commit comments

Comments
 (0)