Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Laravel i code incjection w konstruktorze - po co?
Forum PHP.pl > Forum > Przedszkole
konrados
Cześć.

Analizuję framework Laravel, i kolejna rzecz nie daje mi spokoju.

Tworząc klasę kontrolera zauważyłem, że większość ludzi pobiera jako jego parametry instancje różnych klas potrzebnych do dalszego działania.

Czyli mamy np. coś takiego:

  1. class AdminController extends Controller {
  2.  
  3.  
  4. protected $someObject;
  5.  
  6. /**
  7.   * Create a new AdminController instance.
  8.   *
  9.   * @return void
  10.   */
  11. public function __construct(SomeClass $someObject)
  12. {
  13. $this->someObject = $someObject;
  14. }
  15. (...)


I tu mam pytanie - po co to? W jaki sposób to ulepsza nasz kod? Czy nie lepiej napisać:
  1. public function __construct()
  2. {
  3. $this->someObject = new someClass();
  4. }

?

Jest bardziej znajome, nie trzeba się uczyć nowej składni. Czy może są jakieś zalety, których nie dostrzegam?
Pyton_000
No to tak:
1. Nie uzależniasz obiektu kasy od innych klas. Wiąże się to z SOLID
2. Testowanie. Możesz testować klasę. Jako parametr wtedy przekazujesz Moc, Stub czy inne cuda.
3. Nikt nie każe używać tego, jednak możesz przekazać Interfejs jako Typ a w samym Laravel zdefiniować implementację której używasz. Dzięki temu zmieniasz implementację w jednym miejscu a nie we wszystkich klasach które używają go.
4. Dzięki temu możesz zainicjować np. obiekt który stanie się Singletonem defacto nie będąc nim. Np. Klasa Repozytorium która przechowuje metody pobierające jakieś dane. Nie musisz tworzyć z niej defacto singletona. Wystarczy że zdefiniujesz jej zachowanie w 1 linijce w jakimś ServiceProvider i już mamy singleton. A jak nam się odwidzi to usuwamy model zachowania i już mamy zwykłe zachowanie.

To tak na szybko co mi wpadło do głowy smile.gif
konrados
Dzięki, wiedziałem, że jak chodzi o Laravel, to Ty odpowiesz:)

Punktu pierwszego z początku nie rozumiałem, zrozumiałem jak przeczytałem punkt 3 z parametrem typu interfejs i potem przekazywaniem innej klasy dziedziczącej z tego interfejsu. Ale, a propos tego punktu 3 - czy dobrze rozumiem, że chodzi o to, że może być wiele takich kontrolerów i możemy jedną linijką zmienić klasę, która jest przekazywana? Ale jak tak, to mam inne pytanie.

Powiedzmy, że chodzi o klasę User, która reprezentuje aktualnie zalogowanego usera. Prawie każdy kontroler tego potrzebuje. I przy tym podejściu, każdy kontroler w konstruktorze musi jako parametr pobierać klasę tego usera. Strasznie dużo pisania, szczególnie, że takich przekazywanych klas może być bardzo dużo. Piszę własny mini-framework, i tam (na razie) poszedłem w innym kierunku: klasa User jest zdefiniowana w "rdzeniu" frameworka, ma takie methody jak login czy logout. Natomiast jest specjalny katalog w katalogu "application" w którym istnieje druga klasa "User", która dziedziczy z frameworkowej klasy User. Z założenia tę klasę user może modyfikować (w przeciwieństwie do tej wersji frameworkowej) i w całej aplikacji ma właśnie używać tej klasy.

Podobnie jest z każdą inną klasą frameworkową - Html, Input, Form etc. Każdą developer może nadpisać.

I teraz, pomijając Twój punkt 2 (dotyczący testowania) - czy moje rozwiązanie nie wydaje się lepsze a przynajmniej prostsze?
Pyton_000
Dzięki wink.gif
Co do...

Cytat(konrados @ 11.06.2015, 19:33:06 ) *
Punktu pierwszego z początku nie rozumiałem, zrozumiałem jak przeczytałem punkt 3 z parametrem typu interfejs i potem przekazywaniem innej klasy dziedziczącej z tego interfejsu. Ale, a propos tego punktu 3 - czy dobrze rozumiem, że chodzi o to, że może być wiele takich kontrolerów i możemy jedną linijką zmienić klasę, która jest przekazywana? Ale jak tak, to mam inne pytanie.


Tak. Do kontrolera (w Laravel 5 także do metody) możesz przekazać Interfejs. Potem w "bootstrap/app.php" definiujesz jaka klasa ma być Wstrzyknięta.

Cytat(konrados @ 11.06.2015, 19:33:06 ) *
Powiedzmy, że chodzi o klasę User, która reprezentuje aktualnie zalogowanego usera. Prawie każdy kontroler tego potrzebuje. I przy tym podejściu, każdy kontroler w konstruktorze musi jako parametr pobierać klasę tego usera. Strasznie dużo pisania, szczególnie, że takich przekazywanych klas może być bardzo dużo. Piszę własny mini-framework, i tam (na razie) poszedłem w innym kierunku: klasa User jest zdefiniowana w "rdzeniu" frameworka, ma takie methody jak login czy logout. Natomiast jest specjalny katalog w katalogu "application" w którym istnieje druga klasa "User", która dziedziczy z frameworkowej klasy User. Z założenia tę klasę user może modyfikować (w przeciwieństwie do tej wersji frameworkowej) i w całej aplikacji ma właśnie używać tej klasy.

Nie wiem o co chodzi smile.gif Ale jeśli chodzi o zalogowanego usera to możesz się dobrać do niego przez:

  1. autch()->user()

To jest helper.

Możesz zawsze nadpisać klasę Users tak jak pisałeś i wtedy w ww. pliku zdefiniować że każde odwołanie do Users z L5 to ma być Twoje Users

Nie wiem czy dobrze zrozumiałem to co napisałeś smile.gif
konrados
Cytat
Nie wiem czy dobrze zrozumiałem to co napisałeś


Chodzi właśnie mi o to:

Cytat
Tak. Do kontrolera (w Laravel 5 także do metody) możesz przekazać Interfejs. Potem w "bootstrap/app.php" definiujesz jaka klasa ma być Wstrzyknięta.


To jest koncepcja z Laravela i ja ją teraz rozumiem.

Moja natomiast jest chyba podobna ale inna. Definiujemy klasę "User" w naszej aplikacji, która dziedziczy po klasie "User" we frameworku. I... nic więcej nie trzeba robić. Nie trzeba edytować żadnego pliku typu "bootstrap/app.php" - dlatego, że mój framework sam będzie wiedział, że ma skorzystać z tej klasy napisanej przez developera w katalogu aplikacji.

I właśnie się zastanawiam, czy to nie jest błąd. Bo niby prostsze w użyciu, ale potem może się okazać, że jednak metoda a'la Laravel jest z jakiegoś powodu lepsza...
konrados
No nic, właśnie pomyślałem, że mogę przecież pójść swoją drogą (dziedziczenie zamiast wstrzykiwania) a potem dorobić wstrzykiwanie jeśli kiedyś okaże się, że (oprócz unit tests) są jakieś zalety tego wstrzykiwania.

Dzięki!
memory
@konrados po co potem jak można teraz
konrados
@memory
Bo na razie widzę tylko jedną oczywistą zaletę - testowanie. A to trochę dla mnie za mało, mój framework ma być prosty a dziedziczenie jest proste i wszystkim znane smile.gif

Poza tym na pierwszy rzut oka dołożenie takiego wstrzykiwania nie złamie kompatybilności wstecznej - tzn. dołożę taką możliwość a nadal dotychczasowe rozwiązania będą działały. Czyli nie widzę wad:)
memory
Naprawde warto poczytać o dependency injection
konrados
@memory

Dzięki, ale ja wiem co to jest. Tylko, że w tym konkretnym przypadku do mnie nie przemawia (na razie, wraz z doświadczeniem może przemówi).

com
jak zrozumiesz DI to do Ciebie przemówi, uniezależniasz konkretne klasy od danej konkretnej implementacji. Tworzysz obiekt raz i operujesz w wielu miejscach aplikacji, dzięki temu możesz wywołać jakiegoś configa, czy cokolwiek na nim i masz pewność, że wszystkie dane będą ze sobą spójne. Ponadto możesz mieć kilka implementacji tego samego interfejsu i wykorzystać jeden kod w wielu miejscach bez manipulacji klasą, wystarczy podmienić tylko ten obiekt który przekazujesz.
by_ikar
Jak dla mnie route model binding i form request valdiation są najlepszymi przykładami tego jak wstrzykiwanie obiektów jest przydatne. W kilku linijkach można napisać jakieś rest api, łącznie z validacją (nie tylko danych post), co jest mega.
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.