2011-06-25 12 views
6

Pierwszy przykład:porównujące tablice w PHP - ciekawe zachowanie

$x = array("a" => 1, "b" => 2); 
$y = array("b" => 1, "a" => 2); 
$xLessY = ($x < $y); 
$xGreaterY = ($x > $y); 
var_dump($xLessY, $xGreaterY); 

Wynik: $ xLessY = prawda, $ xGreaterY = prawda

Drugi przykład:

$x = array("a" => 2, "b" => 1); 
$y = array("b" => 2, "a" => 1); 
$xLessY = ($x < $y); 
$xGreaterY = ($x > $y); 
var_dump($xLessY, $xGreaterY); 

: $ xLessY = fałszywe, $ xGreaterY = fałszywe

Według dokumentacji na http://docs.php.net/manual/en/language.operators.comparison.php:

jeśli klucz od argumentu 1 nie znajduje się w argumencie 2 ówczesnego tablice są nieporównywalne, inaczej - porównaj wartość przez wartość

W naszym przypadku każdy klucz z tablicy $ x jest obecny w tablicy $ y, więc $ x i $ y są comp orny. Zobacz także przykład z dokumentacją:

// Arrays are compared like this with standard comparison operators 
function standard_array_compare($op1, $op2) 
{ 
    if (count($op1) < count($op2)) { 
     return -1; // $op1 < $op2 
    } elseif (count($op1) > count($op2)) { 
     return 1; // $op1 > $op2 
    } 
    foreach ($op1 as $key => $val) { 
     if (!array_key_exists($key, $op2)) { 
      return null; // uncomparable 
     } elseif ($val < $op2[$key]) { 
      return -1; 
     } elseif ($val > $op2[$key]) { 
      return 1; 
     } 
    } 
    return 0; // $op1 == $op2 
} 

Takie zachowanie jest bardzo dziwne: $ x jest mniejsze niż $ y i zarazem $ x jest większe niż $ y (pierwszy przykład) i dwie tablice są porównywalne .

Myślę, że to dlatego, że php zawsze porównuje zaczynając od jednej określonej strony znaku "<". Mam na myśli: dla ($ x < $ y) php bierze $ x jako operand 1, dla ($ x> $ y) zajmuje $ y jako operand 1. Chociaż nie znalazłem nic o tym zachowaniu w dokumentacji.
Co sądzisz o tym?

+0

Podejrzewam, że możesz mieć rację co do tego, jaka wartość na spiczastym końcu '<' zostanie użyta jako pierwszy operand. Oczywiście można znaleźć odpowiedź na pewno, jeśli spojrzysz na kod źródłowy PHP ... –

Odpowiedz

0

Mogę się mylić, ale nie sądzę, żebyś mógł porównać tablice w ten sposób. Zawsze zakładałem, że można sprawdzić równość lub nierówność, ale nie można porównać ilości z < i>.

Wydaje się, że man page on array operators to potwierdza.

+0

Istnieje [inna strona podręcznika] (http://php.net/manual/en/language.operators.comparison.php) . Zobacz tabelę "Porównanie z różnymi typami" i tekst poniżej: "Tablica z mniejszą liczbą elementów jest mniejsza, jeśli klucz z argumentu 1 nie został znaleziony w operandzie 2, wtedy tablice są nieporównywalne, w przeciwnym razie - porównaj wartość według wartości (patrz poniższy przykład)" . Istnieje również przykład (funkcja porównania_tabeli_standardowej), który napisałem: – Andy

1

Twoje założenie jest prawidłowe. Operator > jest analizowany jako

| expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); } 

To w zasadzie mówi X > Y jest równoważna not X < Y, co jest oczywiście źle, gdy porównanie nie jest przemienne. Rozważ zgłoszenie tego na bugs.php.net.

+0

Komutacyjny? "X> Y" będące przemienne oznacza, że ​​'X> Y' jest równoważne' Y> X'. Dodatkowo mówisz "porównanie (które porównanie btw) nie jest przemienne" oznacza, że ​​'X> Y' nie jest równoważne' nie X Y' będący równoważnikiem' nie X $ y' i' $ y> $ x' jest prawdziwe z ' $ x! = $ y'. – Artefacto

+0

Zgadzam się, że nie ma sensownego sposobu zamawiania tablic asocjacyjnych, ale to nie znaczy, że dowolna konfiguracja dowolnego porządku nie jest użyteczna - na przykład wiele algorytmów zależy od zamówionych danych. Jednak obecny stan rzeczy polega na tym, że nie tylko nie istnieje całkowity porządek we wszechświecie tablic, ale także tablice, dla których instrukcja stwierdza, że ​​istnieje dobrze zdefiniowana kolejność, w rzeczywistości nie ma spójności między '<' and '>". – Artefacto

1

Nie powiedziałbym, że błąd jest w $x > $y zastępuje $y < $x.

Oczywiście, jeśli zaimplementowano $x > $y w taki sposób, że argumenty nie wymieniały pozycji po przekazaniu do funkcji porównania, rozwiązany zostałby ten konkretny problem. Ale dostajesz drugą w zamian.

Teraz masz:

$x < $y <=> cmp($x, $y) == -1 
$x > $y <=> cmp($y, $x) == -1 

Ponieważ pierwszy klucz z pierwszym argumentem jest zawsze w stosunku pierwsze, oba warunki są spełnione, jeśli reset($x) < $y[key($x)] i reset($y) < $x[key($y)].

jednak rozważyć inną implementację, która rozwiąże ten problem:

$x < $y <=> cmp($x, $y) == -1 
$x > $y <=> cmp($x, $y) == +1 

Teraz < i > są spójne, gdy kolejność argumentów jest stała, ale teraz dostać dziwne zachowanie kiedy zamienić argumenty ponieważ my może nadal mieć wartości cmp($x, $y) == -1 i cmp($y, $x) == -1, co oznaczałoby, że oba są zgodne z ustawieniami $x < $y i $y < $x.

Podsumowując, jedynym rozwiązaniem byłoby naprawienie funkcji porównywania w taki sposób, aby jej zachowanie było antysymetryczne, tj. Tak, aby cmp($x, $y) == - cmp($y, $x), przynajmniej w zestawie elementów, które są uważane za porównywalne.

+0

Myślę, że to zachowanie '$ x <$ y == -1' i' $ y <$ x == -1' jest bardziej zrozumiałe w przypadku nieuporządkowanych tablic. A to jest bardziej zgodne z dokumentacją. – Andy

+0

Może to nie jest błąd, ale powinny to udokumentować – Andy