2010-09-29 11 views
7

wiem korzyści z łączenia wewnątrz PHP, ale powiedzmy, że mamy ten następującą sytuacjęWpływ metody łańcuchowym

$Mail = new MailClass("mail") 
     ->SetFrom("X") 
     ->SetTo("X") 
     ->SetSubject("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->Send(); 

Czy są jakieś problemy z powrotem i ponowne użycie przedmiotu kółko kwestie takie jak prędkości lub nieprzestrzeganie najlepszych praktyk

również warto przeczytać o tym, czy nowy do Fluent-Interface: Martin Fowler on Fluent-Interfaces

W pełni rozumiem, że nie mają być zaprogramowane w ten sposób, i może być traktowane tak:

$Mail = new MailClass("mail"); 
$Mail->AddRecipien(
    array(/*.....*/) 
); 
$Mail->SetFrom("X"); 
$Mail->SetTo("X"); 
$Mail->SetSubject("X"); 
$Mail->Send(); 

ale powiedzmy, że mam obiekt tak:

$Order = new Order() 
     ->With(22,'TAL') 
     ->With(38,'HPK')->Skippable() 
     ->With(2,'LGV') 
     ->Priority(); 

nocie the ->With(38,'HPK')->Skippable(), To jest doskonały przykład Pro do tego typu programowania

+0

Klasy powinny, IMO, potwierdzić swoje argumenty dla instancji i testować/sterować argumentami ich metod. W mojej klasie mailer, is_valid_email jest prywatną metodą wewnątrz klasy. – AutoSponge

+0

"-> Z (38," HPK ") -> Możliwe do pominięcia()" Sytuacja nie stanowi problemu, na przykład w tym scenariuszu/klasie można się dowiedzieć, czy możliwe jest zastosowanie opcji do pominięcia przy dodawaniu. – Hannes

+2

Tak, ale współczynnik czytelności jest większy niż normalne metody kompilacji tego bloku kodu. To jest tylko pro dla czytelności. – RobertPitt

Odpowiedz

5

Jeśli musisz potwierdzić coś, myślę, że to ma więcej sensu potwierdzić to w AddRecipient Meth od siebie, ale wydajność powinna być prawie taka sama. I nie jestem świadomy żadnych ogólnych wad korzystania z łańcuchów metod.

1

EDIT: Aktualizacja odpowiedź dopasować pytanie
rozmowy funkcyjne są wolniejsze niż pętli, czyli łączenia na przykład metoda addRecipient() obniża wydajność odrobinę porównaniu z wywołaniem metody addRecipients() która pobiera tablicę, która jest następnie przetwarzany w pętla.

Co więcej, bardziej wyrafinowana metoda łączenia się z płynnymi interfejsami API może wymagać dodatkowego przechowywania danych związanych z ostatnią wywołaną metodą, aby następne połączenie mogło kontynuować pracę nad tymi danymi, ponieważ wszystkie metody zwracają ten sam obiekt, w którym znajduje się łańcuch. wybudowany. Rzućmy okiem na swoim przykładzie:

... 
->With(22, 'TAL') 
->With(38, 'HPK')->Skippable() 
->With(2, 'LGV') 
... 

Wymaga to, aby pamiętać, że Skippable() ma być stosowana do (38, 'HPK') zamiast (22, 'TAL').

Mimo że Twój kod nie będzie zbyt często wywoływany w pętli lub gdy masz tyle równoczesnych żądań do serwera WWW, że zbliża się do jego limitów (co ma miejsce -load strony internetowe).

Innym aspektem jest to, że metoda łańcuchowego wzorcowania wymusza użycie wyjątków do błędów sygnału (co nie jest złe, różni się od klasycznego stylu kodowania w stylu "zadzwoń i sprawdź wynik").

Zwykle istnieją funkcje, które dają inne wartości niż obiekt, do którego należą (np. Te, które zwracają status obiektu i akcesorów). Ważne jest, aby użytkownik interfejsu API mógł określić, które funkcje są łańcuchowe i które nie muszą bez odniesienia się do dokumentacji za każdym razem, gdy napotka nową metodę (np. Wytyczne, które mówią, że wszystkie mutatory i tylko mutatory obsługują łańcuchowanie).


odpowiedzi do pierwotnego pytania:

[...] The issues i have with chaining is the fact that you cant really perform extra validation [...]

Ewentualnie wdrożenie dedykowanego metodę sprawdzania, które nazywamy po ustawieniu wszystkich właściwości i mieć to powrót szereg niepowodzeń walidacji (co mogą być zwykłymi ciągami lub obiektami, na przykład o nazwie ValidationFailure).

0

To miecz obosieczny.

Dobra strona? Jest to czystsze niż ponowne adresowanie klasy i chociaż jest to głównie zmiana w składni, przyspieszy to trochę przetwarzanie. Byłoby lepiej zapętlić ten rodzaj łańcucha niż zapętlić każde wywołanie w postaci długiej.

Zła strona? Spowoduje to problemy z bezpieczeństwem, gdy ludzie po raz pierwszy się do tego przyzwyczają. Bądźcie pilni w oczyszczaniu nadchodzących vars, abyście nie przekazywali czegoś tam, nie powinniście. Nie komplikuj swoich zajęć.

  1. Wstępnie zatwierdź swoje dane.
  2. Dokonaj automatycznej autoryzacji użytkowników.

Nie widzę problemu z łączeniem tych metod w pętlę, pod względem wydajności.

2

Nie możesz łańcuch bezpośrednio z klasy instancji:

$Mail = new MailClass("mail") 
      ->SetFrom("X") 
      ->SetTo("Y"); 

trzeba instancji, potem łańcuch przeciwko instancja obiektu:

$Mail = new MailClass("mail") ; 
$Mail->SetFrom("X") 
    ->SetTo("Y"); 

Jeśli walidacji w ramach poszczególnych metod dostępowych (tak, jak powinieneś), musisz upewnić się, że zgłaszasz wyjątki po napotkaniu błędu sprawdzania poprawności. Nie można po prostu zwrócić wartości logicznej fałszu w przypadku błędu, w przeciwnym razie łańcuch spróbuje wywołać następną metodę z instancją boolowską, a nie klasową, a otrzymasz.

Fatal error: Call to a member function SetSubject() on a non-object in C:\xampp\htdocs\oChainTest.php on line 23

jeśli generują wyjątki, można owinąć łańcuch w try ... catch

$Mail = new MailClass("mail"); 
try { 
    $Mail->SetFrom("X") 
     ->SetTo("Y") 
     ->SetSubject("Z"); 
} catch (Exception $e) { 
    echo $e->getMessage(); 
} 

ale jako ostrzeżenie, to opuszczenie instancji w częściowo zaktualizowanym stanie, nie ma wycofywania (chyba że piszesz samemu) dla metod, które sprawdziły/wykonały się pomyślnie, a metody śledzące wyjątek nie zostaną wywołane.

+2

Rozwiązaniem tego problemu jest użycie fabrycznych metod do tworzenia instancji obiektów i łańcuchów z tego miejsca, np. 'MailClass :: create ('mail') -> setFrom ('X')'. Minusem w wersjach PHP przed 5.3 jest to, że nie mają późnego wiązania statycznego, tzn. Metody statyczne odnoszą się do klasy, w której zostały zdefiniowane. Ponadto wywołania metod statycznych są powolne. – Archimedix

+0

@Archimedix - poprawny punkt, a późniejsze wiązanie statyczne będzie darem niebios (kiedy mogę wymusić, że moje biblioteki są zawsze uruchamiane przeciwko wersji 5.3+) –

+0

Zawsze używam rejestru abstrakcyjnego ze statycznymi metodami do tworzenia instancji obiektów i zapisywania ich w tablicy tak, aby moim wyjściem byłby 'Rejestr :: Użyj (" Mail ") -> X() -> Y-> Z();' gdzie inicjalizacja odbywa się w ramach metody: 'Rejestr :: Użyj (" Poczta ")' – RobertPitt