Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Przekazanie argumentów do konstruktora
Forum PHP.pl > Forum > PHP > Object-oriented programming
amii
To wycinek z quickstart ze strony Zenda -> http://framework.zend.com/manual/en/learni...eate-model.html
Ogólnie mamy klasę modelu, która wygląda tak (zamieszczam tylko istotne fragmenty):

  1. class Application_Model_Guestbook
  2. {
  3.  
  4. public function __construct(array $options = null)
  5.  
  6. {
  7. if (is_array($options)) {
  8.  
  9. $this->setOptions($options);
  10.  
  11. }
  12.  
  13. }
  14.  
  15.  
  16.  
  17. public function setOptions(array $options)
  18.  
  19. {
  20.  
  21. $methods = get_class_methods($this);
  22.  
  23. foreach ($options as $key => $value) {
  24.  
  25. $method = 'set' . ucfirst($key);
  26.  
  27. if (in_array($method, $methods)) {
  28.  
  29. $this->$method($value);
  30.  
  31. }
  32.  
  33. }
  34.  
  35. return $this;
  36.  
  37. }
  38.  
  39.  
  40. }


Następnie w kontrolerze

  1. class GuestbookController extends Zend_Controller_Action
  2.  
  3. {
  4.  
  5. // snipping indexAction()...
  6.  
  7.  
  8.  
  9. public function signAction()
  10.  
  11. {
  12.  
  13. $request = $this->getRequest();
  14.  
  15. $form = new Application_Form_Guestbook(); //tworzymy obiekt formularza
  16.  
  17.  
  18.  
  19. if ($this->getRequest()->isPost()) {
  20.  
  21. if ($form->isValid($request->getPost())) {
  22.  
  23. $comment = new Application_Model_Guestbook($form->getValues()); //tworzymy model i dostarczamy mu tablicę z wartościami pobranymi z formularza
  24.  
  25. $mapper = new Application_Model_GuestbookMapper();
  26.  
  27. $mapper->save($comment);
  28.  
  29. return $this->_helper->redirector('index');
  30.  
  31. }
  32.  
  33. }
  34.  
  35.  
  36.  
  37. $this->view->form = $form;
  38.  
  39. }
  40.  
  41. }


Pytanie
1. Co robi metoda setOptions i dlaczego zwraca $this?
Ilware
Zend ma bardzo dobrą dokumentację :
http://framework.zend.com/manual/1.11/en/z...ut.options.html
smentek
Cytat(amii @ 16.08.2011, 10:42:43 ) *
Pytanie
1. Co robi metoda setOptions i dlaczego zwraca $this?



Metoda setOptions() wywołuje "magicznie" metody ustawiające (settery), które posiada Application_Model_Guestboo.

Przykładowo po przekazaniu do niej tablicy

  1. array('email' =>'some@email.com')

Zostanie wywołana metoda
  1. public function setEmail($email)
  2. {
  3. $this->_email = (string) $email;
  4. return $this;
  5. }


z parametrem $email = 'some@email.com'

To pozwala na inicjalizację całego obiektu przez przekazanie odpowiedniej tablicy asocjacyjnej bez 'ręcznego' wywoływania wszystkich metod ustawiających.

Zwrócenie przez metodę $this oznacza że zwracany jest cały obiekt co pozwala na tz. fluent interface czyli
  1. $obiekt->metoda1('x')->metoda2('y')->metoda3('z');


Staraj się unikać tego typu mechanizmów. Fluent interface może się czasem nadać ale konstrukcje takie jak setOptions() omijał bym z daleka. Zwięzłość zapisu można osiągnąć w lepszy (bardziej czytelny) sposób.
Zyx
Czemu niby unikać fluent interface? W językach takich, jak PHP, gdzie kompilator nie wykonuje żadnych optymalizacji, jest to nawet sposób na szybsze wykonanie dużej liczby operacji na tym samym obiekcie.
smentek
Cytat(Zyx @ 20.08.2011, 08:52:54 ) *
Czemu niby unikać fluent interface? W językach takich, jak PHP, gdzie kompilator nie wykonuje żadnych optymalizacji, jest to nawet sposób na szybsze wykonanie dużej liczby operacji na tym samym obiekcie.


"Unikać" nie znaczy "nigdy nie używać".

Ze względu na obniżenie czytelności kodu. Chociaż można znaleźć opinie o tym jak to method chaingin i fluent interface mają teoretycznie poprawić czytelność kodu. Czytelny kod to jednak między innymi to, że czytając syngaturę metody wiesz od razu co dana metoda robi ponieważ metoda swoją nazwą opisuje co dokładnie robi. Tymczasem w method chainging nie wiesz co dana metoda robi dopóki nie zjedziesz wzrokiem do instrukcji return. Tak że fluent interface może co najwyżej odrobinę zwiększyć szybkość kodowania dla programisty który DOBRZE ZNA api i jest świadomy że korzysta ono z tego typu rozwiązania.

Nie rozumiem co masz na myśli pisząc o szybszym wykonaniem operacji na obiekcie przez interpreter? Nawet jeżeli method chainging miało by powodować szybsze wykonanie kodu to nie była by to różnica warta uwagi.
mike
Cytat(smentek @ 20.08.2011, 23:55:02 ) *
Ze względu na obniżenie czytelności kodu. Chociaż można znaleźć opinie o tym jak to method chaingin i fluent interface mają teoretycznie poprawić czytelność kodu. Czytelny kod to jednak między innymi to, że czytając syngaturę metody wiesz od razu co dana metoda robi ponieważ metoda swoją nazwą opisuje co dokładnie robi. Tymczasem w method chainging nie wiesz co dana metoda robi dopóki nie zjedziesz wzrokiem do instrukcji return. Tak że fluent interface może co najwyżej odrobinę zwiększyć szybkość kodowania dla programisty który DOBRZE ZNA api i jest świadomy że korzysta ono z tego typu rozwiązania.
No bez jaj. To już problem nazywającego metody, że czytelnie nie nazwał tongue.gif A nie problem doboru rozwiązania.
Dużo częściej użycie fluent interfaces w kontekście na przykład takiego Buildera jest opisywane jako zwiększenie czytelności.
Żeby nie być gołosłownym: Factories, Builders and Fluent Interfaces
smentek
Cytat(mike @ 22.08.2011, 13:04:50 ) *
No bez jaj. To już problem nazywającego metody, że czytelnie nie nazwał tongue.gif A nie problem doboru rozwiązania.
Dużo częściej użycie fluent interfaces w kontekście na przykład takiego Buildera jest opisywane jako zwiększenie czytelności.
Żeby nie być gołosłownym: Factories, Builders and Fluent Interfaces


Ja o pierniku a Ty o wiatraku smile.gif Application_Model_Guestbook jest obiekem "biznesowym". Jeżeli uważasz że fluent interface na seterach obiektu biznesowego poprawia czytelność to nie mogę się zgodzić. A jeżeli o wzorcach z pod linku to inna sprawa. Naprawdę rzadko zdarzają się sytuacje gdzie method chaining wnosi jakąś rzeczywistą wartość. w 95% przypadków lepiej jest zainicjalizować stan obiektu przez konstruktor. Tak że nie rozumiem dlaczego w tutorialach zend framework autorzy mieszają ludziom w głowie wprowadzając tam te mechanizmy...
darko
Method chaining - czy używać czy nie - to jest kwestia gustu. Jeśli mamy dobre api, opisowe nazewnictwo metod to śmiało można korzystać. Przekazywanie przez konstruktor jest dobre do czasu czyli do momentu, w którym danych do przekazania jest stosunkowo mało (retoryczne: co jest czytelniejsze przekazanie jednej mega-wielkiej tablicy do konstruktora czy wywołanie po kolei dziesięciu i więcej dobrze nazwanych metod, z których każda może jeszcze dodatkowo zrobić coś z danymi "po drodze"?).
smentek
1. Gdzie jest wieksze prawdopodobienstwo wystapienia bledu? Przy inicjalizacji przez konstruktor (w jednym miejscu) czy przy wielu metodach gdzie jednej z nich mozemy zapomniec uzyc?
2. Gdzie pojawiaja sie wieksze sprzezenia? (uzycie metod obiektu A w obiekcie B ) przy wywolaniu jedej metody ala konstruktor czy przy wywolaniu wielu seterow?
3. W ktorym wypadku mamy przez chwilę nie spojny (nie w pelni zainicjalizowany obiekt) w przypadku konstruktora czy seterow?
4. Odnosnie wielu argumentow. Jaki obiekt jest dorby taki o waskim zakresie odpowiedzialnosci (w praktyce == malo argumentow) czy superklasa ktora robi wiele roznych rzeczy (w praktyce == wiecej argumentow)
mike
Cytat(smentek @ 22.08.2011, 21:07:50 ) *
Ja o pierniku a Ty o wiatraku smile.gif Application_Model_Guestbook jest obiekem "biznesowym". Jeżeli uważasz że fluent interface na seterach obiektu biznesowego poprawia czytelność to nie mogę się zgodzić. A jeżeli o wzorcach z pod linku to inna sprawa.
Z tym się zgodzę smile.gif
darko
Ad 1-3 tak samo, pamiętajmy, że przyjmujemy dobrze skonstruowane api, w którym programista porusza się niemal z zamkniętymi oczami, nie ma problemu żeby wywoływać po kolei logicznie ponazywane metody, w kolejności takiej, jak intuicyjnie byśmy wykonywali dany zestaw czynności prostych składających się na operację złożoną. Poza tym chainingu nie używa się na niezainicjowanym obiekcie, tylko właśnie w celu jego "kompleksowej" inicjalizacji.
Ad 4 mieszasz trochę bajki, zarówno konstruktor, jak i settery w jednakowym zakresie stanowią o zakresie odpowiedzialności danej klasy, w końcu operują na tych samych danych w obszarze jednego i tego samego obiektu; równie dobrze mógłbyś wywoływać łańcuchowo sekwencję metod na obiektach różnych klas, uzyskując ten sam rezultat.
smentek
Cytat
mieszasz trochę bajki, zarówno konstruktor, jak i settery w jednakowym zakresie stanowią o zakresie odpowiedzialności danej klasy, w końcu operują na tych samych danych w obszarze jednego i tego samego obiektu;


Ale chciałem zwrócić uwagę, że prawidłowy obiekt najczęściej nie ma aż tak wielu danych aby przekazywanie ich w konstruktorze było problemem. Także argument, który tu padł o dużej tablicy przekazywanej do konstruktora jest stawianiem wozu przed koniem. Dobry obiekt to względnie mała ilość argumentów w konstruktorze a więc brak problemu ze zbyt duża ilością zmiennych w konstruktorze. Setery stają się zbędne.

Cytat
równie dobrze mógłbyś wywoływać łańcuchowo sekwencję metod na obiektach różnych klas, uzyskując ten sam rezultat.


Rozumiem że mowisz o sytuacji w ktorej obiekt zwraca iny obiekt a ten inny obiekt zwraca jeszcze inny? i mozemy sobie wykonac cos w rodzaju:

  1. $a->getB()->getC()->multiplyCbyX(x)->print();


Jasne takie api też jest czasami potrzebne ale znowu w 5% bo w 95% będzie niepotrzebnym łamaniem hermetyzacji.

Tak że nie należy pisać na forach, że fluent interfac z method chaining czy przekazywanie w konstruktorze to bez znaczenia. Czytają to ludzie którzy nie widzą różnicy. Jak dostaną informacje że powinni unikać geterów i seterów to będzie to z pożytkiem dla nich.
darko
Wnioskując po Twoich postach wydaje się, że nie rozumiesz podstawowej różnicy pomiędzy przekazaniem argumentu do konstruktora, a chainingiem. Method chaining pozwala na wykonywanie pewnych złożonych operacji według dowolnej kolejności, na kilka różnych sposobów (czego przekazanie tablicy do konstruktora nie oferuje), co pozwala na większą elastyczność w kodowaniu. To samo lub podobne osiągnąć można na kilka różnych sposobów operując jedynie w umiejętny sposób kolejnością wywoływania metod. Teraz pomyśl, jak musiałbyś się nagimnastykować implementując jeden konstruktor, aby użytkownikowi API umożliwić chociaż zbliżoną elastyczność.
smentek
Cytat(darko @ 23.08.2011, 21:23:55 ) *
Wnioskując po Twoich postach wydaje się, że nie rozumiesz podstawowej różnicy pomiędzy przekazaniem argumentu do konstruktora, a chainingiem. Method chaining pozwala na wykonywanie pewnych złożonych operacji według dowolnej kolejności, na kilka różnych sposobów (czego przekazanie tablicy do konstruktora nie oferuje), co pozwala na większą elastyczność w kodowaniu. To samo lub podobne osiągnąć można na kilka różnych sposobów operując jedynie w umiejętny sposób kolejnością wywoływania metod. Teraz pomyśl, jak musiałbyś się nagimnastykować implementując jeden konstruktor, aby użytkownikowi API umożliwić chociaż zbliżoną elastyczność.


No to po podsumujmy:

1. "Przekazywanie tablicy do konstruktora" to jest idea którą Ty w swoim poście wprowadziłeś do tego wątku. Wprowadziłeś ją jako argument za tym że method chaining czy fluent interface pozwala uniknąć takich dużych tablic w konstruktorze.

2. Ja ten argument "zbiłem" tym, że prawidłowe obiekty nie mają tego typu problemów. Zwróciłem też uwagę, że nie możemy powiedzieć "używać czy nie używać method haining to bez znaczenia" bo mechanizm ten (MC) ma też swoje koszty.

3. Wyciągasz z tego wniosek, że nie rozumiem do czego służy method chaining i piszesz dalej:

Cytat
Method chaining pozwala na wykonywanie pewnych złożonych operacji według dowolnej kolejności, na kilka różnych sposobów (...) Teraz pomyśl, jak musiałbyś się nagimnastykować implementując jeden konstruktor, aby użytkownikowi API umożliwić chociaż zbliżoną elastyczność.


1. Konstruktor nie ma tu nic do rzeczy bo jak sama nazwa wskazuje służy do 'konstruowania' a nie do 'wywoływania'.
2. Wykonywanie złożonych operacji według dowolnej kolejności możemy osiągnąć poprzez wywoływanie 'normalnych' metod na obiekcie.

Prawda?

Także ja mogę nie wiedzieć do czego służy MC ale Ty wiesz. I wiesz też, że nie należy go nadużywać i nie jest tak że konstruktor czy MC to wsio ryba.
darko
Cytat(smentek @ 24.08.2011, 19:32:41 ) *
No to po podsumujmy:

1. "Przekazywanie tablicy do konstruktora" to jest idea którą Ty w swoim poście wprowadziłeś do tego wątku. Wprowadziłeś ją jako argument za tym że method chaining czy fluent interface pozwala uniknąć takich dużych tablic w konstruktorze.

2. Ja ten argument "zbiłem" tym, że prawidłowe obiekty nie mają tego typu problemów. Zwróciłem też uwagę, że nie możemy powiedzieć "używać czy nie używać method haining to bez znaczenia" bo mechanizm ten (MC) ma też swoje koszty.

3. Wyciągasz z tego wniosek, że nie rozumiem do czego służy method chaining i piszesz dalej:



1. Konstruktor nie ma tu nic do rzeczy bo jak sama nazwa wskazuje służy do 'konstruowania' a nie do 'wywoływania'.
2. Wykonywanie złożonych operacji według dowolnej kolejności możemy osiągnąć poprzez wywoływanie 'normalnych' metod na obiekcie.

Prawda?

Także ja mogę nie wiedzieć do czego służy MC ale Ty wiesz. I wiesz też, że nie należy go nadużywać i nie jest tak że konstruktor czy MC to wsio ryba.

To teraz pojechałeś. Po kolei:

1. Bardzo wygodnie było wybrać wypowiedź wyrwaną z kontekstu, gdzie podałem jako jedynie przykład i to w dodatku jako pytanie retoryczne (sic!) i twierdzić, że właśnie taką tezę wniosłem do wątku. Pozostawię to bez zbędnego w tym przypadku komentarza. Każdy rozumuje na swój sposób.

2. jw, a odnośnie kosztów to niestety ze wszystkim tak jest, że coś za coś

3. Nie. Znów nadinterpretujesz. Napisałem, że niepotrzebnie mieszasz w temacie, ale nigdzie nie napisałem, że czegoś nie rozumiesz. Jest różnica?

1. (ponowne) czepiasz się nazewnictwa, zresztą niesłusznie. Przecież obaj wiemy, że tworząc obiekt właśnie wywołujesz (chcąc nie chcąc) specjalną metodę nazywaną konstruktorem, która alokuje dla obiektu pamięć i pozwala zainicjalizować obiekt danymi.

2. (ponowne) W takim razie zapytam czym według Ciebie różni się "normalna" metoda od metody zwracającej wskaźnik (właściwie referencję) do obiektu i tym samym pozwalająca na użycie method chaining? Przecież jedna i druga to takie same metody podlegające tym samym prawom języka. I nie wyskakuj tu proszę z kontrą, że jak zwrócisz referencję, to tym samym zużywasz więcej pamięci. Nawet jeśli to są to mikrosekundy na wydajności i minimalny narzut pamięci (w ogóle w testach wydajnościowych tak niewielkie różnice nie występują), a otrzymujesz narzędzie, które pozwala na olbrzymią elastyczność i swobodę. Zresztą php nigdy nie było wydajnym narzędziem. Zależy Ci na mega-wydajności? Koduj w C++ albo w asemblerze wink.gif

Czyli wychodzi zatem że - nieprawda.

Odnośnie Twojego "podsumowania" to napiszę krótko: daruj sobie tanią ironię, której wcale nie nadrabiasz jakaś szczególną wiedzą (tip: tak dopiero teraz wytykam Ci po raz pierwszy niewiedzę w temacie metod). Ja nigdzie sobie nie roszczę praw do monopolu na wiedzę i nie życzę sobie, żeby ktoś mnie w taki sposób traktował. Jeśli się w czymś mylę - ok przekonaj mnie do swojej racji sensownymi argumentami, a nie jadem.

A teraz lektura do poduszki:
http://www.webgeekly.com/tutorials/php/use...te-neater-code/
http://www.cakemail.com/method-chaining-in-php/
http://stackoverflow.com/questions/3821762...method-chaining
smentek
Piszesz:
Cytat
Nie. Znów nadinterpretujesz. Napisałem, że niepotrzebnie mieszasz w temacie, ale nigdzie nie napisałem, że czegoś nie rozumiesz. Jest różnica?


A wcześniej pisałeś:
Cytat
Wnioskując po Twoich postach wydaje się, że nie rozumiesz podstawowej różnicy pomiędzy przekazaniem argumentu do konstruktora, a chainingiem.


Ja to odczytuje tak jak jest napisane. I to nie jest żaden problem ze Tobie się wydaje że ja czegoś nie rozumiem. Jestem ironiczny to prawda, ale nie ma tu żadnego jadu. smile.gif

Ponadto sam doprowadziłeś do obecnej sytuacji. Przeanalizuj wątek. Ja odnoszę się do kwestii merytorycznych i podaję merytoryczne argumenty na swoje tezy. Jak ktoś pisze głupotę to ja to prostuję odnosząc się do faktów. I robię to nie tylko dla swojego ego ale także ze względu mniej doświadczone osoby, które to czytają. Ciebie w pewnym momencie bardziej zaczęła interesować moja osoba niż temat tego wątku. Także nie kreuj się na ofiarę mojej agresji, to niedorzeczne smile.gif.
darko
offtopic.gif
Cytat(smentek @ 24.08.2011, 21:59:20 ) *
Ja to odczytuje tak jak jest napisane. I to nie jest żaden problem ze Tobie się wydaje że ja czegoś nie rozumiem. Jestem ironiczny to prawda, ale nie ma tu żadnego jadu. smile.gif
Ponadto sam doprowadziłeś do obecnej sytuacji. Przeanalizuj wątek. Ja odnoszę się do kwestii merytorycznych i podaję merytoryczne argumenty na swoje tezy. Jak ktoś pisze głupotę to ja to prostuję odnosząc się do faktów. I robię to nie tylko dla swojego ego ale także ze względu mniej doświadczone osoby, które to czytają. Ciebie w pewnym momencie bardziej zaczęła interesować moja osoba niż temat tego wątku.

Jest jeszcze coś takiego, jak chwyt retoryczny wink.gif
Cytat(smentek @ 24.08.2011, 21:59:20 ) *
Także nie kreuj się na ofiarę mojej agresji, to niedorzeczne smile.gif.

Jakiej agresji? Pokaż, gdzie użyłem słowa "agresja"? Odnosisz się merytorycznie do tematu, twierdząc, że "normalna" metoda (czyt. nie zwracająca referencji na obiekt) różni się od zwracającej referencję do obiektu? Na tej podstawie krytykujesz uparcie method chaining, chociaż założę się, że nawet nie zerknąłeś do ani jednego tekstu w linkach, które podałem. Wykaż mi w takim razie moją "głupotę". Odnieś się przynajmniej do jednego mojego argumentu. Jeśli chodzi o temat, to autor dostał już odpowiedź na swoje pytanie. Z mojej strony EOT, uważam, że dalsza rozmowa z Tobą nie ma sensu. Snorkle.gif
smentek
Oczywiście że zajrzałem pod linki które wstawiłeś. Fakt że nie czytałem treści, jako że już mam szczególną wiedzę na ten temat (żart). wink.gif Czy tracił bym czas pisząc z Tobą gdybym nie traktował cię poważnie?

To jest moja klasa w której użyłem method chaining: https://github.com/smentek/TaskBufferBundle.../TaskBuffer.php (np. linia 92). co dowodzi że nie krytykuję ślepo tego mechanizmu.

Cieszę się że nie odbierasz mnie jako kogoś kto chce ci dokopać. Nie taką miałem intencję.
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.