Bug #71238 [Com]: usort pass by reference inconsistency

From: Date: Sun, 03 Jan 2016 14:46:18 +0000
Subject: Bug #71238 [Com]: usort pass by reference inconsistency
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-198383@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71238&edit=1 ID: 71238 Comment by: white06tiger+PHPbug at gmail dot com Reported by: eugen dot alter at gmail dot com Summary: usort pass by reference inconsistency Status: Open Type: Bug Package: Arrays related Operating System: any PHP Version: 7.0.1 Block user comment: N Private report: N New Comment: I have the same issue with uksort() and WITHOUT modifying the actual array. This bug seems to trigger as soon as anything accesses the array to be sorted. Following code is supposed to sort an array by values and key (in this case, behaves like a stable sort) ``` <?php error_reporting(-1); header('Content-Type: text/plain'); function uasort_key(&$arr, $func) { return uksort($arr, function($a,$b) use(&$arr,$func) { return $func($arr[$a], $arr[$b], $a, $b); }); } function sort_me($a, $b, $ka = 0, $kb = 0) { return ($a < $b ? -1 : ($a > $b ? 1 : ($ka < $kb ? -1 : ($ka > $kb ? 1 : 0)) )); } $test_array = array(4,6,2,1,7,5,1,34,1,0,4); $test_array_uasort = $test_array; $test_array_uasort_key = $test_array; uasort($test_array_uasort, 'sort_me'); uasort_key($test_array_uasort_key, 'sort_me'); echo 'PHP: ', phpversion(), "\n\n"; echo 'Unsorted: '; print_r($test_array); echo 'uasort: '; print_r($test_array_uasort); echo 'uasort_key: '; print_r($test_array_uasort_key); echo "\n\n", 'Source: ', "\n\n"; readfile(__FILE__); ?> ``` In PHP 5.3 you'll get the false-positive warning: “Warning: uksort(): Array was modified by the user comparison function in sort_bug.php on line 8” which got seemingly fixed in bug #50688 for PHP 7.. Maybe said "fix" introduced our current faulty behavior. Expected result (PHP 5.3): ----- uasort_key: Array ( [9] => 0 [3] => 1 [6] => 1 [8] => 1 [2] => 2 [0] => 4 [10] => 4 [5] => 5 [1] => 6 [4] => 7 [7] => 34 ) ----- Actual result (PHP 7.0.1): ----- uasort_key: Array ( [9] => 0 [6] => 1 [3] => 1 [2] => 2 [0] => 4 [1] => 6 [10] => 4 [8] => 1 [5] => 5 [4] => 7 [7] => 34 ) ----- Previous Comments: ------------------------------------------------------------------------ [2015-12-29 18:24:50] levim@php.net Using var_export in PHP 5.5: array ( 0 => array ( 'name' => 'Bar', 'children' => array ( 0 => array ( 'name' => 'X', 'children' => array ( ), ), 1 => array ( 'name' => 'Y', 'children' => array ( ), ), 2 => array ( 'name' => 'Z', 'children' => array ( ), ), ), ), 1 => array ( 'name' => 'Foo', 'children' => array ( 0 => array ( 'name' => 'A', 'children' => array ( ), ), 1 => array ( 'name' => 'B', 'children' => array ( ), ), ), ), ) Using var_export in a slightly outdated master branch: array ( 0 => array ( 'name' => 'Bar', 'children' => array ( 0 => array ( 'name' => 'Z', 'children' => array ( ), ), 1 => array ( 'name' => 'X', 'children' => array ( ), ), 2 => array ( 'name' => 'Y', 'children' => array ( ), ), ), ), 1 => array ( 'name' => 'Foo', 'children' => array ( 0 => array ( 'name' => 'B', 'children' => array ( ), ), 1 => array ( 'name' => 'A', 'children' => array ( ), ), ), ), ) ------------------------------------------------------------------------ [2015-12-29 16:38:59] eugen dot alter at gmail dot com Description: ------------ In PHP 5.4 ... 5.6 passing compared array elements by reference and then changing them from inside comparison function works properly whilst in PHP7 it does not. In sample script: function tries to sort arrays by key "name" on all nested levels. The nested levels are sorted correctly on PHP 5.4 .. 5.6 but not on PHP7. Test script: --------------- $array = [ [ 'name' => 'Foo', 'children' => [ [ 'name' => 'B', 'children' => [] ], [ 'name' => 'A', 'children' => [] ] ] ], [ 'name' => 'Bar', 'children' => [ [ 'name' => 'Z', 'children' => [] ], [ 'name' => 'X', 'children' => [] ], [ 'name' => 'Y', 'children' => [] ] ] ] ]; usort($array, $f = function(&$x, &$y) use (&$f){ usort($x['children'], $f); usort($y['children'], $f); return strcasecmp($x['name'], $y['name']); }); Expected result: ---------------- array(2) { [0]=> array(2) { ["name"]=> string(3) "Bar" ["children"]=> array(3) { [0]=> array(2) { ["name"]=> string(1) "X" ["children"]=> array(0) { } } [1]=> array(2) { ["name"]=> string(1) "Y" ["children"]=> array(0) { } } [2]=> array(2) { ["name"]=> string(1) "Z" ["children"]=> array(0) { } } } } [1]=> array(2) { ["name"]=> string(3) "Foo" ["children"]=> array(2) { [0]=> array(2) { ["name"]=> string(1) "A" ["children"]=> array(0) { } } [1]=> array(2) { ["name"]=> string(1) "B" ["children"]=> array(0) { } } } } } Actual result: -------------- array(2) { [0]=> array(2) { ["name"]=> string(3) "Bar" ["children"]=> array(3) { [0]=> array(2) { ["name"]=> string(1) "Z" ["children"]=> array(0) { } } [1]=> array(2) { ["name"]=> string(1) "X" ["children"]=> array(0) { } } [2]=> array(2) { ["name"]=> string(1) "Y" ["children"]=> array(0) { } } } } [1]=> array(2) { ["name"]=> string(3) "Foo" ["children"]=> array(2) { [0]=> array(2) { ["name"]=> string(1) "B" ["children"]=> array(0) { } } [1]=> array(2) { ["name"]=> string(1) "A" ["children"]=> array(0) { } } } } } ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=71238&edit=1

« previous php.bugs (#198383) next »