Bug #69158 [Com]: Inconsistency: usort does not return the same result on PHP < 7 and PHP7

[email protected] ("gooomax at gmail dot com")
Newsgroups php.bugs
Message-ID <[email protected]>
Edit report at https://bugs.php.net/bug.php?id=69158&edit=1

 ID:                 69158
 Comment by:         gooomax at gmail dot com
 Reported by:        contact at jubianchi dot fr
 Summary:            Inconsistency: usort does not return the same result
                     on PHP < 7 and PHP7
 Status:             Not a bug
 Type:               Bug
 Package:            Arrays related
 PHP Version:        master-Git-2015-03-02 (Git)
 Block user comment: N
 Private report:     N

 New Comment:

So if at php7 this is not a bug - it is a bug on php < 7, isn't it?


Previous Comments:
------------------------------------------------------------------------
[2015-09-07 07:39:08] [email protected]

@matt: As @aharvey said, PHP has never guaranteed a stable sort for "equal" items. If your array was defined in a different order, or if you merely added or removed an item from it, then the result could be in a different order.

There is no reason for pos5 to sort before pos3 besides "that's what happened when the author ran this code in PHP 5". Maybe I'm naive but I'd think the test should verify that each item is <= the next item; that is all that sorting guarantees* and assuming more would be a mistake.

The code is a bit too complex for me to suggest an actual solution, but I'm thinking along the lines of:

  $growth = -99;
  for each $value in the column {
    assert that $value['growth'] >= $growth;
    $growth = $value['growth'];
  }

Or you can guarantee a stable sort by doing a final comparison (ie, when all other comparisons returned equality) on a unique, even if arbitrary, value. Perhaps "label" would fit the bill?

* given a consistent comparison function

------------------------------------------------------------------------
[2015-09-07 06:30:54] matt at piwik dot org

Hello, 

at Piwik we are building the leading open source alternative to Google Analytics.

This change in PHP7 usort function internals, is causing us some trouble. We need our test suite to run on PHP5 and PHP7 and return the same results. Due to this change in "secondary sort order" (maybe not the best name), it isn't possible for us to have test suites work on both PHP version. We have some few dozens tests failing on PHP7 (test outputs on travis are linked from: https://github.com/piwik/piwik/issues/8689#issuecomment-137424173 )

If you could change usort implementation to keep same behavior as PHP5, it would be awesome and would surely help many people like us have test suites run on both PH5 and PHP7 consistently :-)

Keep up the great work!

------------------------------------------------------------------------
[2015-03-02 18:50:13] [email protected]

This is expected: PHP's sorting functions aren't guaranteed to be stable ($a and $b are "equal" in this case, since the array callback will return 0 as their file and line elements are identical), and there have been implementation changes in PHP 7 that affect this case.

------------------------------------------------------------------------
[2015-03-02 14:49:00] contact at jubianchi dot fr

Description:
------------
There is a tiny difference on usort result between php < 7 and php7 (master): items are not ordered the same way between those versions.

PHP7 seems to be consistent with HVVM but not with earlier version of PHP :)

Test script:
---------------
<?php

// http://3v4l.org/RYTt9

$array = array(
    array(
        'file' => 'file1',
        'line' => 1,
        'message' => 'foo'
    ),
    array(
        'file' => 'file1',
        'line' => 1,
        'message' => 'bar'
    )
);

usort($array, function($a, $b) {
        if ($a['file'] !== $b['file'])
        {
            return strcmp($a['file'], $b['file']);
        }
        else if ($a['line'] === $b['line'])
        {
            return 0;
        }
        else
        {
            return ($a['line'] < $b['line'] ? -1 : 1);
        }
    }
);

var_dump($array);

Expected result:
----------------
array(2) {
  [0]=>
  array(3) {
    ["file"]=>
    string(5) "file1"
    ["line"]=>
    int(1)
    ["message"]=>
    string(3) "bar"
  }
  [1]=>
  array(3) {
    ["file"]=>
    string(5) "file1"
    ["line"]=>
    int(1)
    ["message"]=>
    string(3) "foo"
  }
}

Actual result:
--------------
array(2) {
  [0]=>
  array(3) {
    ["file"]=>
    string(5) "file1"
    ["line"]=>
    int(1)
    ["message"]=>
    string(3) "foo"
  }
  [1]=>
  array(3) {
    ["file"]=>
    string(5) "file1"
    ["line"]=>
    int(1)
    ["message"]=>
    string(3) "bar"
  }
}


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=69158&edit=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.