Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Porównywanie obiektów - Dziwne
Forum PHP.pl > Forum > PHP > Object-oriented programming
mstraczkowski
Testując sobie mój własny moduł do walidacji natknąłem się na pewien problem, którego nie potrafię wyjaśnić.
Albo ja jestem przemęczony, albo PHP świruje i to kolejne z jego "FUCK LOGIC"
Może ktoś wie co jest grane i o co może chodzić ?

Mianowicie chodzi o porównywanie obiektów, w dokumentacji możemy przeczytać:

Cytat
Comparing Objects

In PHP 5, object comparison is more complicated than in PHP 4 and more in accordance to what one will expect from an Object Oriented Language (not that PHP 5 is such a language).

When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values, and are instances of the same class.


Na prostym przykładzie możemy zobaczyć zachowanie tej zależności

  1. class A
  2. {
  3. protected $property;
  4.  
  5. public function __construct($value)
  6. {
  7. $this->property = $value;
  8. }
  9. }
  10.  
  11. $object1 = new A('ABC');
  12. $object2 = new A('XYZ');
  13.  
  14. // Instances are not equal because of different value of property
  15. var_dump($object1 == $object2); // Will return bool(false)

Ok, PHP stwierdził, że obiekty nie są sobie równe - zgadza się.
Więc teraz użyłem obiektów mojej klasy, przekazałem różne wartości parametrów do konstruktora
Wartości parametrów są umieszczane we właściwościach klasy.

  1. echo "Start";
  2.  
  3. // Creating an instance of class with some parameters
  4. // Each of parameter will be stored as class property
  5. $object1 = new ComparsionRule('ABadasdC', ComparsionRule::LESS_THAN_OR_EQUAL);
  6.  
  7. // Creating an instance of class with some different parameters
  8. // Each of parameter will be stored as class property
  9. $object2 = new ComparsionRule('XYZ', ComparsionRule::NOT_EQUAL_TO);
  10.  
  11. // Two instances should not be equal (false expected)
  12. var_dump($object1 == $object2); // Will return bool(true)
  13.  
  14. // Printing content of first object
  15. var_dump($object1);
  16.  
  17. // Printing content of second object
  18. var_dump($object2);
  19.  
  20. // Checking the expression again
  21. // Two instances should not be equal (false expected)
  22. var_dump($object1 == $object2); // Will return bool(false)
  23.  
  24. echo "End";

Wynik jest zaskakujący, najpierw PHP stwierdza, że obiekty są sobie równe
Następnie wyświetla te obiekty i ponownie sprawdza czy są sobie równe, ale tym razem stwierdza, że jednak nie są równe
Załączam screenshot, na którym widać zawartość obu obiektów oraz te dziwne chwiejne wyniki porównania



SmokAnalog
Czy gdzieś po drodze do akcji nie wkraczają metody magiczne? Trudno tak zgadywać bez kodu klasy.
mstraczkowski
Nie, nie używam zbyt często metod magicznych ze względu na wsparcie dla IDE i dla jasności kodu.
Jedyne metody magiczne, które są zaimplementowane i dotyczą także tej klasy to __construct() i __invoke()

Dla testu usunąłem metode __invoke(), jednak problem występuje nadal.
Kodu klasy niestety nie mogę udostępnić publicznie.

Kolejna ciekawostka:
Jeżeli usunę właściwość $_errorDefinitions to wtedy zachowanie wraca do normy.
Wygląda to tak jakby PHP analizował tylko pierwszą napotkaną właściwośc i tylko ją porównywał.

Podobnie jeżeli zamienie kolejność tj. type i compareValue zdefiniuje wcześniej niż errorDefinitions
em1X
Po co porównywać dwa obiekty? Zobacz jak robi to Java. Utwórz sobie interfejs, np.
  1. interface Comparable
  2. {
  3. /**
  4.   * @param object $object Obiekt do porównania
  5.   * @returns bool Czy obiekty są identyczne
  6.   */
  7. public function equals($object);
  8. }


i sam definiuj kiedy obiekty rzeczywiście są podobne:
  1. class Person implements Comparable
  2. {
  3. protected $name;
  4.  
  5. public function __construct($name)
  6. {
  7. $this->name=$name;
  8. }
  9.  
  10. public function getName()
  11. {
  12. return $this->name;
  13. }
  14.  
  15. public function equals($object)
  16. {
  17. return $this->getName() === $object->getName();
  18. }
  19. }
  20.  
  21. $andrzej=new Person('Andrzej');
  22. $monika=new Person('Monika');
  23.  
  24. var_dump($andrzej->equals($monika));
mstraczkowski
Po to, aby sprawdzić czy taka instancja z takimi samymi właściwościami istnieje już w danej puli obiektów.

Mówiąc bardziej po ludzku:
W tym konkretnym przypadku, aby sprawdzić czy została już zdefiniowana taka sama reguła walidacyjna (instancja tej samej klasy z takimi samymi właściwościami)

Celem mojego tematu nie było otrzymanie alternatywnych rozwiązań, bo z tym nie mam problemu (rozwiązań jest sporo)
Chciałem tylko poznać odpowiedź na pytanie: "Dlaczego PHP w tej sytuacji tak się zachowuje"

Twój kod fajnie wygląda na banalnych przykładach, jednak w przypadku bardziej abstrakcyjnych rozwiązań
I dosyć sporej ilości klas nie za bardzo mam ochotę dokładać kolejny interfejs i implementować samodzielnie podobieństwa między obiektami
Tym bardziej, że PHP i jego dokumentacja deklaruje się, że operator porównania może to zrobić za mnie.

Doraźnie zastosowałem serializację obiektów i wyliczenie na jej podstawie sumy kontrolnej md5 w celu porównywania instancji
Zdaję sobie sprawę z tego, że nie jest to najlepsze rozwiązanie, ale tak jak mówię jest to rozwiązanie doraźne.

@edit 04.01.2014

Tak jak słusznie podejrzewałem, jest to bug w PHP
Zostawiam więc post dla potomnych smile.gif

https://bugs.php.net/bug.php?id=66286
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.