@@ -103,6 +103,7 @@ PHP_MINIT_FUNCTION(array) /* {{{ */
103
103
104
104
REGISTER_LONG_CONSTANT ("SORT_REGULAR" , PHP_SORT_REGULAR , CONST_CS | CONST_PERSISTENT );
105
105
REGISTER_LONG_CONSTANT ("SORT_NUMERIC" , PHP_SORT_NUMERIC , CONST_CS | CONST_PERSISTENT );
106
+ REGISTER_LONG_CONSTANT ("SORT_STRICT" , PHP_SORT_STRICT , CONST_CS | CONST_PERSISTENT );
106
107
REGISTER_LONG_CONSTANT ("SORT_STRING" , PHP_SORT_STRING , CONST_CS | CONST_PERSISTENT );
107
108
REGISTER_LONG_CONSTANT ("SORT_LOCALE_STRING" , PHP_SORT_LOCALE_STRING , CONST_CS | CONST_PERSISTENT );
108
109
REGISTER_LONG_CONSTANT ("SORT_NATURAL" , PHP_SORT_NATURAL , CONST_CS | CONST_PERSISTENT );
@@ -349,6 +350,65 @@ static zend_always_inline int php_array_data_compare_unstable_i(Bucket *f, Bucke
349
350
}
350
351
/* }}} */
351
352
353
+ /* return int to be compatible with compare_func_t */
354
+ static int hash_zval_strict_function (zval * z1 , zval * z2 ) /* {{{ */
355
+ {
356
+ // The most important thing about this comparison mode is that the result
357
+ // is 0 when zend_is_identical, and non-zero otherwise.
358
+ if (zend_is_identical (z1 , z2 )) {
359
+ return 0 ;
360
+ }
361
+ // Below this point, the return value should always be non-zero.
362
+ // First try to use a "normal" comparison.
363
+ int c = zend_compare (z1 , z2 );
364
+ if (c != 0 ) {
365
+ return c ;
366
+ }
367
+ // If the types are different, compare based on type.
368
+ int t1 = Z_TYPE_P (z1 );
369
+ int t2 = Z_TYPE_P (z2 );
370
+ if ( t1 != t2 ) {
371
+ return (t1 < t2 ) ? -1 : 1 ;
372
+ }
373
+ switch (t1 ) {
374
+ case IS_ARRAY :
375
+ // Do a recursive comparison
376
+ return zend_hash_compare (
377
+ Z_ARRVAL_P (z1 ), Z_ARRVAL_P (z2 ),
378
+ (compare_func_t ) hash_zval_strict_function , 1 /* ordered */
379
+ );
380
+
381
+ case IS_OBJECT :
382
+ {
383
+ // First compare on class name, as that's consistent across runs
384
+ zend_string * name1 = Z_OBJCE_P (z1 )-> name ;
385
+ zend_string * name2 = Z_OBJCE_P (z2 )-> name ;
386
+ c = zend_binary_strcmp (name1 -> val , name1 -> len , name2 -> val , name2 -> len );
387
+ if (c != 0 ) {
388
+ return (c < 0 ) ? -1 : 1 ;
389
+ }
390
+ // Fall back on spl_object_id() value, which will probably vary
391
+ // non-deterministically between runs (alas).
392
+ zend_object * obj1 = Z_OBJ_P (z1 );
393
+ zend_object * obj2 = Z_OBJ_P (z2 );
394
+ ZEND_ASSERT (obj1 -> handle != obj2 -> handle );
395
+ return (obj1 -> handle < obj2 -> handle ) ? -1 : 1 ;
396
+ }
397
+
398
+ default :
399
+ ZEND_ASSERT (0 && "Value types should have consistent == and ===" );
400
+ return 0 ;
401
+ }
402
+ }
403
+ /* }}} */
404
+
405
+
406
+ static zend_always_inline int php_array_data_compare_strict_unstable_i (Bucket * f , Bucket * s ) /* {{{ */
407
+ {
408
+ return hash_zval_strict_function (& f -> val , & s -> val );
409
+ }
410
+ /* }}} */
411
+
352
412
static zend_always_inline int php_array_data_compare_numeric_unstable_i (Bucket * f , Bucket * s ) /* {{{ */
353
413
{
354
414
return numeric_compare_function (& f -> val , & s -> val );
@@ -405,6 +465,7 @@ DEFINE_SORT_VARIANTS(key_compare_string_case);
405
465
DEFINE_SORT_VARIANTS (key_compare_string );
406
466
DEFINE_SORT_VARIANTS (key_compare_string_locale );
407
467
DEFINE_SORT_VARIANTS (data_compare );
468
+ DEFINE_SORT_VARIANTS (data_compare_strict );
408
469
DEFINE_SORT_VARIANTS (data_compare_numeric );
409
470
DEFINE_SORT_VARIANTS (data_compare_string_case );
410
471
DEFINE_SORT_VARIANTS (data_compare_string );
@@ -527,6 +588,14 @@ static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type, int
527
588
}
528
589
break ;
529
590
591
+ case PHP_SORT_STRICT :
592
+ if (reverse ) {
593
+ return php_array_reverse_data_compare_strict ;
594
+ } else {
595
+ return php_array_data_compare_strict ;
596
+ }
597
+ break ;
598
+
530
599
case PHP_SORT_REGULAR :
531
600
default :
532
601
if (reverse ) {
@@ -591,6 +660,14 @@ static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_t
591
660
}
592
661
break ;
593
662
663
+ case PHP_SORT_STRICT :
664
+ if (reverse ) {
665
+ return php_array_reverse_data_compare_strict_unstable ;
666
+ } else {
667
+ return php_array_data_compare_strict_unstable ;
668
+ }
669
+ break ;
670
+
594
671
case PHP_SORT_REGULAR :
595
672
default :
596
673
if (reverse ) {
0 commit comments