PHP - usort изменяет содержимое объектов в массиве, как мне это предотвратить? - PullRequest
6 голосов
/ 12 декабря 2010

Я использую usort с функцией сравнения пользователей для сортировки массива объектов.После запуска usort для массива этих объектов я обнаружил, что некоторые значения объектов изменились вместе с их положением в массиве.Что мне не хватает?Я не верю, что в моей функции сравнения пользователей есть побочные эффекты.Разве usort как-то деконструирует / реконструирует объекты?

Вот функция сравнения пользователей, которую я использую:

<code>private function SortArrayOfSegments($segments){
    foreach($segments as $segment){
        echo '<pre>';
        var_dump($segment);  
    }
    usort($segments, "AirObject::CompareSegments");
    foreach($segments as $segment){
        var_dump($segment);
        echo '
';} вернуть $ сегменты;} открытая статическая функция CompareSegments ($ a, $ b) {$ interval = date_diff (date_create ($ a-> StartDateTime-> GetString ()), date_create ($ b-> StartDateTime-> GetString ()));if ($ interval-> invert == 1) {return 1;} иначе если ($ интервал-> у == 0 && $ интервал-> м == 0 && $ интервал-> d == 0 && $ интервал-> я == 0 && $ интервал-> с == 0 && $интервал-> h == 0) {возврат 0;} else if ($ interval-> invert == 0) {return -1;}}

Используемые мной объекты выглядят следующим образом:

object(AirSegment)#14 (12) {
      ["StartDateTime"]=>
      object(VDateTime)#27 (4) {
        ["date"]=>
        string(10) "2010-12-07"
        ["time"]=>
        string(8) "09:23:21"
        ["timezone"]=>
        string(0) ""
        ["utc_offset"]=>
        string(0) ""
      }
      ["EndDateTime"]=>
      object(VDateTime)#23 (4) {
        ["date"]=>
        string(10) "2010-12-07"
        ["time"]=>
        string(8) "13:23:21"
        ["timezone"]=>
        string(0) ""
        ["utc_offset"]=>
        string(0) ""
      }
      ["start_airport_code"]=>
      string(3) "SFO"
      ["start_city_name"]=>
      string(13) "San Francisco"
      ["end_airport_code"]=>
      string(3) "STL"
      ["end_city_name"]=>
      string(8) "St Louis"
      ["operating_airline"]=>
      string(15) "United Airlines"
      ["operating_flight_number"]=>
      string(3) "335"
      ["duration"]=>
      float(NAN)
      ["required_properties":protected]=>
      array(9) {
        ["StartDateTime"]=>
        bool(false)
        ["EndDateTime"]=>
        bool(false)
        ["start_airport_code"]=>
        bool(false)
        ["end_airport_code"]=>
        bool(false)
        ["operating_airline"]=>
        bool(false)
        ["operating_flight_number"]=>
        bool(false)
        ["start_city_name"]=>
        bool(false)
        ["end_city_name"]=>
        bool(false)
        ["service_class"]=>
        bool(true)
      }
      ["service_class"]=>
      string(5) "Coach"
      ["trip_id"]=>
      string(4) "1621"
    }

Изменяемое свойство является свойством duration.Перед запуском usort каждый объект имеет допустимое значение с плавающей запятой.После usort два из них - NaN.

РАЗРЕШЕНИЕ:

date_diff имеет побочные эффекты - по крайней мере, в моей сборке PHP.Удаление полностью исправило проблемы.

public static function CompareSegments($a, $b){
    $adate = new DateTime($a->StartDateTime->GetString());
    $bdate = new DateTime($b->StartDateTime->GetString());
    $lessThan = $adate < $bdate;
    $equal = $adate == $bdate;
    $greaterThan = $adate > $bdate;

    if($lessThan){
        return -1;  
    }else if($equal){
        return 0;   
    }else{
        return 1;   
    }
}

Ответы [ 2 ]

1 голос
/ 12 декабря 2010

Вдобавок ко всему, я не вижу там ничего, что могло бы изменить содержимое самих элементов массива.

Способ работы usort() заключается в том, что когда он определяет новый порядок элементов, он добавляет новые элементы в массив, который содержит значение оригиналов, а затем удаляет оригиналы, так что строго говоря ни один из элементов массива, который вы передали в функцию, никогда не появляется, только их копии (хотя и как часть той же переменной массива, которую вы передали).

Я не вижу причин, по которым usort будет разрушать и перестраивать объекты, как вы и просили, но это делает нечто подобное с самим массивом. Насколько я могу судить, ничего в значении элементов массива не должно быть изменено, если вы не сделаете это явно в функции сравнения.

В вашем методе CompareSegments вы вызываете метод StartDateTime->GetString(). Возможно ли, что метод GetString() изменяет ваши данные?

0 голосов
/ 14 декабря 2010

Как выглядят объекты перед применением метода usort или любого другого метода?Без знания исходного состояния объектов трудно быть убедительным, но NaN - это ошибочный результат, полученный функцией, переданной usort.

...