Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Pytanie Dotyczące OOP
Forum PHP.pl > Forum > PHP > Object-oriented programming
frytek92
Witam

  1.  
  2. $oop = new test_class;
  3.  
  4. $oop->funkcja()->funkcja();
  5.  


Moje pytanie do czego służy takie wywoływanie metody ?, kiedy się to stosuje może jakiś przykład klasy w której mamy takie zastosowanie bo nie mogę pojąc dlaczego metody są wywoływane w taki sposób czyli "$oop->funkcja()->funkcja()"

Pozdrawiam
wookieb
Praktycznie w każdej klasie ma to zastosowanie. Ładnie to wygląda w kodzie i nie trzeba za każdym razem przepisywać referencji do obiektu.
Spawnm
Cytat(frytek92 @ 29.08.2010, 14:45:20 ) *
... może jakiś przykład klasy w której mamy takie zastosowanie...

Chyba wszystkie klasy db tak mają
$rows=$db->from('table')->findAll( $ofset, 5);
Tak jest szybciej i czytelniej smile.gif
Crozin
Cytat
Moje pytanie do czego służy takie wywoływanie metody ?
Takie czyli jakie? Przecież to najnormalniejsze w świecie wywołanie metody na obiekcie i następnie wywołanie kolejnej na zwróconym obiekcie.
Cytat
bo nie mogę pojąc dlaczego metody są wywoływane w taki sposób czyli "$oop->funkcja()->funkcja()"
Kod
a = 1 + 2 + 3;

VS

a = 1;
a += 2;
a += 3;
To jest ta sama sytuacja - wyrażenia można łączyć.


Jeżeli natomiast metody jednego obiektu mają być "łączone" wtedy mamy do czynienia z tak zwanym fluent interface
frytek92
Wielkie dzięki zrozumiałem o co chodzi, temat do zamknięcia.

Pozdrawiam
smentek
Chyba warto by jeszcze dodać, że kodowanie w tym stylu CZĘSTO, nie jest dobrym rozwiązaniem. Można nawet powiedzieć że najczęściej będzie no oznaką słabego stylu kodowania.

Na tego typu Kod:
  1. $parowoz->wagonPierwszy()->wagonDrugi()->wagonTrzeci();


Anglosasi mają ukuty termin "train carsh". Wrak pociągu.

Na chłopski rozum: z reguły warto sprawdzić czy metoda, która miała zwrócić obiekt faktycznie go zwróciła. Zwłaszcza jeżeli zwaracane obiekty zależą od aktualnego stanu bazy.

Ponadto tego typu kod łamie podstawową zasade OOP o enkapsulacji obiektów. Staramy się Powiedzieć obiektowi co ma robić a nie wyciągać z niego bebechy a potem wyciągać bebechy z jego bebechów...

Z drugiej strony jeżeli uznamy że nie działamy na obiektach a na strukurach danych to w pewnych specyficznych sytuacjach powyższe rozwiązanie jest to do przyjęcia. Np. Język DQL w ORM doctrine...
wookieb
Czy ty wiesz do czego służy method chaining oraz wiesz co to wyjątki? Czy wyczytałeś na jakimś blogu i bez zastanowienia powtarzasz?
smentek
Cytat(wookieb @ 8.09.2010, 20:42:49 ) *
Czy ty wiesz do czego służy method chaining oraz wiesz co to wyjątki? Czy wyczytałeś na jakimś blogu i bez zastanowienia powtarzasz?


Czytałem na Twoim tongue.gif. A tak poważnie, to co wiem a czego nie wiem jest nieistotne, jeśli chcesz się wypowiedzić pod moim adresem (także krytycznie) to odnieś się do tematu na który dyskutujemy najlepiej bez personalnych ataków. I poświęć temu więcej niż 2 zdania.
wookieb
Cytat
Ponadto tego typu kod łamie podstawową zasade OOP o enkapsulacji obiektów. Staramy się Powiedzieć obiektowi co ma robić a nie wyciągać z niego bebechy a potem wyciągać bebechy z jego bebechów...

Gdzie ty tu widzisz złamanie zasadę enkapsulacji? Ja osobiście nigdzie.
Żeby było więcej niż dwa zdania dopowiem, że świat dotyka problem braku pszczół spowodowany dziwnym zjawiskiem uciekania wspomnianych osobników z uli.
mike
~wookieb są dwa aspekty takiego kodowania. Jeśli stosujemy typowe fluent interface to jest OK.
Jednym słowem kolejne wywołania na (tym samym) obiekcie tej samej klasy są w porządku.

Natomiast jeśli każda wywołanie jest na obiekcie innej klasy: $obiektKlasyA()->$obiektKlasyB()->$obiektKlasyC(); to już źle. I raczej powinno się tego unikać.
wookieb
Cytat(mike @ 8.09.2010, 22:26:13 ) *
Natomiast jeśli każda wywołanie jest na obiekcie innej klasy: $obiektKlasyA()->$obiektKlasyB()->$obiektKlasyC(); to już źle. I raczej powinno się tego unikać.

Czyli rozumiem, że takie wywołanie jest złe?
  1. $form = new Form();
  2. $form->addElement(new Form_Element_Select('nazwa_pola')) // addElement nadal zwraca $form
  3. ->getElement('nazwa_pola')
  4. ->setValue('test');

Oczywiście istota problemu zaczyna się od getElement. Jeżeli tak to dlaczego?
-=Peter=-
smentek wyczytał to nie z blogu, a najprawdopodobniej z książki Czysty kod winksmiley.jpg @smentek - zwróć uwagę, że tutaj został poruszony temat fluent interface, czyli że każde wywołanie metody powoduje zwrócenie obiektu, na którego rzecz ta metoda została wywołana. Nie odpytujemy się obiektu x po to aby dostać obiekt y, z którego pobierzemy obiekt z. Tutaj cały czas operujemy na tym samym obiekcie. To jest całkowicie inna sytuacja, żadna zasada (enkapsulacji, demeter, czy Bóg wie czego) nie jest tutaj łamana winksmiley.jpg Tym tokiem rozumowania np. wzorce builder, query object, specification, które często korzystają z fluent interface (np. obiekt Doctrine_Query) jest objawem złego stylu kodowania...
Crozin
Cytat
Natomiast jeśli każda wywołanie jest na obiekcie innej klasy: $obiektKlasyA()->$obiektKlasyB()->$obiektKlasyC(); to już źle. I raczej powinno się tego unikać.
Tak dla jasności, chodzi o przykładowo coś takiego:
  1. File file = new PlainTextFile("plik");
  2. Line line = file.getLine(0);
  3. String[] words = line.getWords();
  4. String word = words[0];
  5.  
  6. # VS
  7.  
  8. String word = new PlainTextFile("plik").getLine(0).getWords()[0];
Przykład trochę lipny, ale mamy tu do czynienia z trzema typami jakiś tam obiektów (plus tablica). W sumie przy jakiś dłuższych tasiemcach drugi zapis mógłby być nieco zbyt skomplikowany, jednak z reguły kończą się one na dwóch, trzech, maks. czterech metodach. Czy poza ewentualną czytelnością zapisu jakieś inne ale są? Bo nieco mnie zaintrygowałeś.

EDIT:
Ojej... na przyszłość muszę odświeżać temat przed dodaniem odpowiedzi, a nie po 10 minutach odpisywać tongue.gif
smentek
To prawda -=Peter=- w "Czysty Kod" był o tym rozdział. winksmiley.jpg. Ale przecież sam na końcu swego postu podałem buildera z doctrine za przykład kiedy tego typu zapis bywa do zaakceptowania. Dlatego piszę "często" a nie "zawsze".
I prawdą jest to co piszę, że tego typu zapis niewłaściwie stosowany często kończy się kraksą.
Dzięki za odzew.
-=Peter=-
@Crozin - tutaj raczej chodzi o:
  1. String word = new PlainTextFile("plik").getLine(0).getWords()[0];
  2.  
  3. //vs
  4.  
  5. String word = new PlainTextFile("plik").getFirstWordFromLine(0);
  6. //lub bardziej ogólnie
  7. String word = new PlainTextFile("plik").getWordFromLine(0, 0);


Chodzi o to, że w pierwszym przypadku odkrywamy implementację klasy PlainTextFile, to że obiekt tej klasy składa się z obiektów Line.

Inny bardziej jaskrawy przykład:
  1. class newsActions
  2. {
  3. public function doSave(...)
  4. {
  5. //... coś tam robię i na końcu przekierowanie
  6. $this->getController()->redirect(...);//"wraki pociągów" ;)
  7. //vs
  8. $this->redirect(...);
  9. }
  10. }


ukrywamy to, że korzystamy z front controllera aby zrobić przekierowanie. Np. w testach jednostkowych łatwiej nam w razie potrzeby przesłonić jedną metodę aby zrobić jakąś zaślepkę, niż przesłaniać dwie metody. Poza tym taki kod jest bardziej odporny na zmiany, bo co jeśli metoda redirect z kontrolera (zwróconego przez getController) zostanie przeniesiona gdzieś indziej? Czekają nas zmiany w wielu miejscach, zamiast w jednym, gdyż klasy są mocno zależne od siebie.
Crozin
Hmm... tworzenie takich metod proxy jest jak najbardziej OK w przypadku takich właśnie pierdół jak "redirect". Jednak w nieco bardziej skomplikowanych przypadkach (ot chociażby już ten daremny przykład z plikiem/liniami/słowami) to już raczej średni pomysł:
1. Obiekt "nadrzędny" (tu PlainTextFile) nagle musiałby zawierać dziesiątki metod proxy
2. Obiekt ten utraciłby swoje znaczenie - nagle (z punktu widzenia interfejsu) stałby się jakimś potworkiem od wielu rzeczy
3. Koniec końców i tak pewnie wystąpiłaby metoda getLines()

Nie zgodziłbym się też tak do końca z tym odkrywaniem implementacji. To nie jest wyciąganie bebechów, tylko raczej wyciągnięcie udostępnianych danych (w tym przykładzie obiekty typu File pełniły niejako role kolekcji z dodatkowymi informacjami dot. tej kolekcji).

Zgodzę się za to z tym, że takie ukrywanie "pół-bebechów" przynosi pewne korzyści - jednak ma to swoją cenę.
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.