Skip to content

Commit 4dad419

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Support enums in array_unique
2 parents 581e729 + 35c1bb2 commit 4dad419

File tree

3 files changed

+133
-1
lines changed

3 files changed

+133
-1
lines changed

Zend/tests/gh9775_1.phpt

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
GH-9775: Backed 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+
$instructorsAdmin = Test::INSTRUCTORS_ADMIN;
19+
20+
$data = [
21+
Test::COURSES_ADMIN,
22+
Test::COURSES_REPORTING_ACCESS,
23+
Test::BUNDLES_ADMIN,
24+
Test::USERS_ADMIN,
25+
Test::B2B_DASHBOARD_ACCESS,
26+
Test::B2B_DASHBOARD_ACCESS,
27+
Test::INSTRUCTORS_ADMIN,
28+
&$instructorsAdmin,
29+
Test::COUPONS_ADMIN,
30+
Test::AUTHENTICATED,
31+
];
32+
33+
$data = array_unique($data, flags: SORT_REGULAR);
34+
35+
var_dump($data);
36+
37+
?>
38+
--EXPECT--
39+
array(8) {
40+
[0]=>
41+
enum(Test::COURSES_ADMIN)
42+
[1]=>
43+
enum(Test::COURSES_REPORTING_ACCESS)
44+
[2]=>
45+
enum(Test::BUNDLES_ADMIN)
46+
[3]=>
47+
enum(Test::USERS_ADMIN)
48+
[4]=>
49+
enum(Test::B2B_DASHBOARD_ACCESS)
50+
[6]=>
51+
enum(Test::INSTRUCTORS_ADMIN)
52+
[8]=>
53+
enum(Test::COUPONS_ADMIN)
54+
[9]=>
55+
enum(Test::AUTHENTICATED)
56+
}

Zend/tests/gh9775_2.phpt

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

ext/standard/array.c

+21-1
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,27 @@ static zend_always_inline int php_array_key_compare_string_locale_unstable_i(Buc
290290

291291
static zend_always_inline int php_array_data_compare_unstable_i(Bucket *f, Bucket *s) /* {{{ */
292292
{
293-
return zend_compare(&f->val, &s->val);
293+
int result = zend_compare(&f->val, &s->val);
294+
/* Special enums handling for array_unique. We don't want to add this logic to zend_compare as
295+
* that would be observable via comparison operators. */
296+
zval *rhs = &s->val;
297+
ZVAL_DEREF(rhs);
298+
if (UNEXPECTED(Z_TYPE_P(rhs) == IS_OBJECT)
299+
&& result == ZEND_UNCOMPARABLE
300+
&& (Z_OBJCE_P(rhs)->ce_flags & ZEND_ACC_ENUM)) {
301+
zval *lhs = &f->val;
302+
ZVAL_DEREF(lhs);
303+
if (Z_TYPE_P(lhs) == IS_OBJECT && (Z_OBJCE_P(lhs)->ce_flags & ZEND_ACC_ENUM)) {
304+
// Order doesn't matter, we just need to group the same enum values
305+
uintptr_t lhs_uintptr = (uintptr_t)Z_OBJ_P(lhs);
306+
uintptr_t rhs_uintptr = (uintptr_t)Z_OBJ_P(rhs);
307+
return lhs_uintptr == rhs_uintptr ? 0 : (lhs_uintptr < rhs_uintptr ? -1 : 1);
308+
} else {
309+
// Shift enums to the end of the array
310+
return -1;
311+
}
312+
}
313+
return result;
294314
}
295315
/* }}} */
296316

0 commit comments

Comments
 (0)