File tree Expand file tree Collapse file tree 4 files changed +135
-1
lines changed Expand file tree Collapse file tree 4 files changed +135
-1
lines changed Original file line number Diff line number Diff line change @@ -27,6 +27,8 @@ PHP NEWS
2727- Standard:
2828 . Fixed bug GH-10990 (mail() throws TypeError after iterating over
2929 $additional_headers array by reference). (nielsdos)
30+ . Fixed bug GH-9775 (Duplicates returned by array_unique when using enums).
31+ (ilutov)
3032
313313 Apr 2023, PHP 8.1.18
3234
Original file line number Diff line number Diff line change 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+ }
Original file line number Diff line number Diff line change 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+ }
Original file line number Diff line number Diff line change @@ -345,7 +345,27 @@ static zend_always_inline int php_array_key_compare_string_locale_unstable_i(Buc
345345
346346static 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 enums handling for array_unique. We don't want to add this logic to zend_compare as
350+ * that would be observable via comparison operators. */
351+ zval * rhs = & s -> val ;
352+ ZVAL_DEREF (rhs );
353+ if (UNEXPECTED (Z_TYPE_P (rhs ) == IS_OBJECT )
354+ && result == ZEND_UNCOMPARABLE
355+ && (Z_OBJCE_P (rhs )-> ce_flags & ZEND_ACC_ENUM )) {
356+ zval * lhs = & f -> val ;
357+ ZVAL_DEREF (lhs );
358+ if (Z_TYPE_P (lhs ) == IS_OBJECT && (Z_OBJCE_P (lhs )-> ce_flags & ZEND_ACC_ENUM )) {
359+ // Order doesn't matter, we just need to group the same enum values
360+ uintptr_t lhs_uintptr = (uintptr_t )Z_OBJ_P (lhs );
361+ uintptr_t rhs_uintptr = (uintptr_t )Z_OBJ_P (rhs );
362+ return lhs_uintptr == rhs_uintptr ? 0 : (lhs_uintptr < rhs_uintptr ? -1 : 1 );
363+ } else {
364+ // Shift enums to the end of the array
365+ return -1 ;
366+ }
367+ }
368+ return result ;
349369}
350370/* }}} */
351371
You can’t perform that action at this time.
0 commit comments