php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69866 usort call with same keys problem
Submitted: 2015-06-18 03:45 UTC Modified: 2015-06-18 08:04 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: dmifedorenko at gmail dot com Assigned:
Status: Not a bug Package: Arrays related
PHP Version: 7.0Git-2015-06-18 (Git) OS: Linux vm 3.13.0-37-generic #64-U
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: dmifedorenko at gmail dot com
New email:
PHP Version: OS:

 

 [2015-06-18 03:45 UTC] dmifedorenko at gmail dot com
Description:
------------
Different usort behavior in php5.6 and php7.

5.6 returns first array element, and 7 returns last element.

Test script:
---------------
$results = array(
  array(2001, 1),
  array(2002, 1),
);

usort($results, function ($a, $b) {
	return $a[1] > $b[1] ? -1 : 1;
});

var_dump($results[0][0]);

Expected result:
----------------
int(2001)

Actual result:
--------------
int(2002)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-06-18 05:42 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2015-06-18 05:42 UTC] requinix@php.net
usort() does not produce stable results if the comparison function is inconsistent. Your function claims that both items in $result should sort after the other so you'll get different results with different initial orders.

If you make your function behave properly then not only will you get the "right" result but you'll get it in every version of PHP. For example, you could do
  return $b[1] - $a[1];

Note that sorting this way will claim both items are equal and, just like what happens with an inconsistent comparison function, their sort order will be undefined and thus vary with the initial ordering.
Obviously if you took both numbers into consideration then that wouldn't happen:
  return ($b[1] - $a[1]) ?: ($b[0] - $a[0]);
 [2015-06-18 06:09 UTC] dmifedorenko at gmail dot com
Thank you for the answer.

We have a lot of code in our project. Of course we can fix some fallen unit tests, but due to the fact that this code _always_ worked stable in 5.5 and 5.6 is necessary to review all 84 cases using usort in our project.

Perhaps some of them expect the old behavior and will have problems with PHP7.

Are you sure this is our problem and not backward compatible issue?
 [2015-06-18 06:52 UTC] requinix@php.net
Unfortunately yes. Try with different sizes of arrays and the items in different orders and you'll see the result vary.

PHP 7 will bring a number of big internal changes, and apparently those influenced usort() which I say because I don't know of any deliberate changes to it, but the fact is that your code was relying on undefined behavior.
 [2015-06-18 08:04 UTC] nikic@php.net
The changes to usort() (and all other sorting functions) were indeed deliberate -- we now use a different sort implementation. This implementation will use insertion sort for small arrays (rather than the usual quicksort). Both algorithms have different comparison sequences and stability attributes.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 12:01:30 2024 UTC