Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Co zwracać, kiedy nie mamy czego?
Forum PHP.pl > Forum > PHP > Object-oriented programming
Sedziwoj
Zacznę od kodu
  1. <?php
  2. class Anubis {
  3.  
  4. }
  5. class Cos {
  6. public function zrob( Anubis $a ){
  7.  
  8. }
  9. }
  10. class Zwrotna {
  11. /**
  12.  * @param boolean $oki
  13.  * @return Anubis
  14.  */
  15. public function daj( $oki ){
  16. if( $oki ){
  17. return new Anubis();
  18. }else{
  19. return null;
  20. }
  21. }
  22. }
  23. $z = new Zwrotna();
  24. $c = new Cos();
  25. $c->zrob( $z->daj( true ) );
  26. $c->zrob( $z->daj( false ) );
  27. ?>


Wszystko fajnie, tylko że nie działa :] (PHP 5.2.4)

No właśnie, co zwracać jeśli nie mamy co?
Na przykład pobierz artykuły, w normalnej sytuacji zwracamy iterator/array z artykułami, ale jak nie mamy tych artykułów, to zwracamy pustą "kolekcję"?
Bo PDO tego np. nie robi zwraca null.
Ale jak mamy zwrócić konkretny obiekt to nie możemy zwrócić niezainicjalizowanego, więc czy chcemy czy nie musimy null, na pewno lepsze niż -1 snitch.gif, w wyjątek jest od szczególnej sytuacji, nie jak tylko np. brak artykułów.
LBO
Ten zabieg ma na celu jedynie podpowiadanie typu, nie ma żadnej logiki - zapobiega niedbalstwu.

Jeżeli używasz "type hinting" to musisz być pewny, że zmienna będzie właśnie określonego typu. Dlatego twój przykład tak naprawdę jest niepoprawny.

edit:

Nie możesz zapominać, że istnieją funkcje: is_a" title="Zobacz w manualu PHP" target="_manual, get_class" title="Zobacz w manualu PHP" target="_manual etc.
Cysiaczek
Wiem, że to hardcore, ale jakiś czas temu wprowadziłem klasę devNull, która robi za obiekt - przydatna tam, gdzie na zwróconym obiekcie próbujemy wywołać jakąś metodę - nie dostajemy wówczas fatal errora, tylko możemy sami określić, co ma się dziać. Ja tego używam w szablonach, gdy jeden szablon formularza jest używany do edycji i do wstawiania nowego wpisu
  1. <?php
  2. if(!is_object($post))
  3. {
  4. $post=new devNull();
  5. }
  6. ?>


Wiem, że nie zawsze takie coś jest przydatne, ale mozna to troszkę rozwinąc i np,
  1. <?php
  2. class Anubis {
  3.  
  4. }
  5.  
  6. class nullAnubis extends Anubis
  7. {
  8. function __construct(){}
  9. function __call(){}
  10. }
  11.  
  12. class Cos {
  13. public function zrob( Anubis $a ){
  14.  
  15. }
  16. }
  17. class Zwrotna {
  18. /**
  19.  * @param boolean $oki
  20.  * @return Anubis
  21.  */
  22. public function daj( $oki ){
  23. if( $oki ){
  24. return new Anubis();
  25. }else{
  26. return new nullAnubis();
  27. }
  28. }
  29. }
  30. $z = new Zwrotna();
  31. $c = new Cos();
  32. $c->zrob( $z->daj( true ) );
  33. $c->zrob( $z->daj( false ) );
  34. ?>


Pozdrawiam.
Sedziwoj
Cytat(LBO @ 20.12.2007, 16:36:40 ) *
Ten zabieg ma na celu jedynie podpowiadanie typu, nie ma żadnej logiki - zapobiega niedbalstwu.
Jeżeli używasz "type hinting" to musisz być pewny, że zmienna będzie właśnie określonego typu. Dlatego twój przykład tak naprawdę jest niepoprawny.


Tylko że z tego co wiem to w Java analogiczny kod będzie działać (tam dopiero jakby w metodzie Cos::zrob() próbować wywołać metodę na null by wyrzuciło błąd).
Do tego powiedz mi gdzie mam źle napisane?
Bo przecież tak powinno się pisać obiektowo, a nie sprawdzanie wszędzie zwracanych wartości, bo kod robi się nieczytelny.
Więc niedbalstwo raczej nie jest z mojej strony, bo gdybym musiał sprawdzać za każdym razem co zwraca jakaś metoda to byłby burdel. Przyjmowanie danych z parametrów czy zewnętrznych trzeba sprawdzać, ale to się robi wewnątrz kodu metody, a nie za każdym razem gdy się ją używa.

@Cysiaczek

To jest obejście problemu, nie rozwiązanie.
Do tego bym raczej napisał coś w tym stylu
  1. <?php
  2. class nullAnubis extends Anubis {
  3.  public $nullAnubis = true;
  4.  public function __construct(){}
  5.  public function __call(){
  6. throw new Exception( 'To nie obiekt, to null ;P' );
  7.  }
  8. }
  9. ?>

Aby móc określić czy to jest "null", jak również zapobiec błędom.
Ale mi się i tak takie rozwiązanie nie podoba.
LBO
Sedziwoj,, w Javie może i tak, ale nie w PHP.

PHP nie ma nawet natywnego obiektu, po którym dziedziczą wszystkie inne, a Ty byś chciał takie bajery.

Zadałeś pytanie, odpowiedziałem, nie da się, nie działa.

Podpatrz większe projekty, typu Zend Framework, Agavi, mimo, że to arcydzieło obiektówki w PHP funkcje o których napisałem wyżej idą w użycie często.
Sedziwoj
@LBO
Co nie znaczy że jest dobre, do tego
Cytat
Note: The is_a() function is deprecated as of PHP 5 in favor of the instanceof type operator.


W Java możesz przekazywać typy podstawowe (jak dobrze pamiętam) więc nie wszystko dziedziczy po Object().
LBO
Wróćmy do początku:
Działa Tobie Twój przykład? Nie działa.
Cysiaczek podał Tobie alternatywę/workaround? Podał, ale jesteś niezadowolony. Zrozum, że PHP to nie Java, a obiektówka kuleje.

Cytat
Note: The is_a() function is deprecated as of PHP 5 in favor of the instanceof type operator.


No to nie używaj is_a, tylko instance_of. Nie wiem czemu się tego czepiasz. Masz zestaw funkcji do rozpoznawania typów to Ich używaj - to była moja rada - mniejsza o szczegóły.

Cytat
W Java możesz przekazywać typy podstawowe (jak dobrze pamiętam) więc nie wszystko dziedziczy po Object().


Pominę, że znów się czepiasz, ale wydaje mi się, że wszystkie.
dr_bonzo
1. Jest wzorzec NullObject (cos jak Cysiaczkody devNull)
2. Skoro znasz kontrakty wejsciowe i wyjsciowe metody daj() to wiesz ze ona moze zwracac null'a, i musisz ta sytuacje obsluzyc
Sedziwoj
@dr_bonzo
Właśnie w tym problem, że tego się nie podaje, że może zwrócić null. Tak jak podane PDO->query() które zwraca też null, gdy robi się przykład z manuala to działa, ale jak chcesz to co zwróciło przekazać i dopiero potem iterować, to już musisz spr. czy nie jest null, a w dokumentacji nic o zwracaniu null nie mówi. (Co śmieszniejsze gdyby zwróciło pusty obiekt PDOStatement wszystko by działało).

Mimo wszystko dzięki za pomoc.

W sumie to trochę odeszliśmy od tematu. Bo chodziło mi co zwracać z metod, kolega powiedział "null przy braku wyniku", z tym się zgadzam jeśli ma byś zwrócony "normalny" obiekt, ale co do kolekcji czy iteratorów mam pewne wątpliwości.
nevt
Sedziwoj... w OOP siedzę już od bardzo dawna, od czasów Borland C++, potem Delphi, MS Visual Studio, Java, C# a teraz bawię się w PHP - świat się zmienia - trzeba się dostosowywać...

twoje podejście jest błędne w podstawowym założeniu - nie należy tworzyć metod obiektów które zwracają różne typy danych - wtedy właśnie pojawiają się wszystkie możliwe, opisane powyżej komplikacje, z koniecznością każdorazowego sprawdzania co dana metoda zwróciła na czele...

jeżeli wynikiem działania metody ma być obiekt - to ta metoda MUSI zwracać obiekt... a nie NULL, czy FALSE czy -1... jeżeli NIE JEST W STANIE stworzyć tego obiektu - wywołuje wyjątek z odpowiednim błędem... jeżeli program ma dalej się wykonywać pomimo wystąpienia tego błędu - przechwytujesz wyjątek i obsługujesz...

ja w każdym razie od lat stosuję 3 proste zasady w przypadku niemożności zwrócenia właściwego wyniku działania metody:
1. jeżeli metoda zwraca typ prosty (int, string, itp) - to może zwracać NULL jako sytuację szczególną oznaczającą brak danych lub wartość spoza zakresu...
2. jeżeli metoda zwraca typ iterowany (tablicę) - to zwraca pustą tablicę array() - z regóły takie dane poddawane są w dalszej części kodu obróbce w pętlach i w naturalny sposób unikamy błędów...
3. jeżeli metoda ma zwracać jakiś zasób lub obiekt - uchwyt do pliku, do bazy danych, do kontrolera itp. nie zwraca NULL, tylko wywołuje wyjątek - bo przecież ten zasób / obiekt jest niezbędny w dalszej części kodu...

pozdrawiam.
mike
Nie wiem skąd w ogóle pomysł zwracania różnych typów/struktur danych.
Przecież to czysta głupota.

Jeśli nie ma co zwrócić to zwracamy null. Ewentualnie czasem możemy sobie pozwolić na pusty obiekt.
Na przykład jeśli miała to być tablica to zwracamy pustą. Jeśli to miał być zainicjowany obiekt, to zwracamy pusty (ale nie null). Czasem się przydaje.
Sedziwoj
@mike & nevt
Właśnie mi brak pewności siebie ;P
Bo chodzi o to co podałem, przykłady bibliotek które tak robią, wydawało mi się to dziwne, dlatego spytałem, bo na mój rozum jest coś nie tak.
Bo nawet wspomniane PDO co zwraca null, to metoda go nie zwraca u mnie, tylko pusty obiekt, dzięki czemu nie robię dalej zbędnych warunków.
Pomysł nie jest mój, ale jak wszystko co dowiaduję się od osób "mądrzejszych" od siebie, a mi coś nie pasuje, dochodzę.
Bo takie zwracanie null ma miejsce też w Propel, co też przysporzyło mi "problemów", ale coraz bardziej mam wrażenie że Propel jest kiepsko obiektowo napisany, kolejna rzecz po wyjątkach (czy raczej wyjątku).

Co do zwracania null zamiast typów prostych, to jak już tak robić to konsekwentnie stosować to co Cysiaczek zaproponował. Jeśli się nie podoba, to nie widzę powodu inaczej traktowania braku danych w postaci obiektu i typu podstawowego.
Co do kolekcji (tablica/iterator), to mam podobną opinię, że powinno się ją zwrócić, co najwyżej pustą (a czego PDO nie robi).

P.S. Lubię takie dyskusje, każdy da swoje 3gr a na piwo starczy winksmiley.jpg tzn. można się czegoś dowiedzieć i zrewidować swoje poglądy (czasem nie programistyczne, ale na temat np. panującego zacofania)
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.