Nie jestem programistą PHP, więc zastanawiam się, czy w PHP bardziej popularne jest używanie jawnego gettera / settera, w czystym stylu OOP, z polami prywatnymi (tak jak lubię):
class MyClass {
private $firstField;
private $secondField;
public function getFirstField() {
return $this->firstField;
}
public function setFirstField($x) {
$this->firstField = $x;
}
public function getSecondField() {
return $this->secondField;
}
public function setSecondField($x) {
$this->secondField = $x;
}
}
lub po prostu pola publiczne:
class MyClass {
public $firstField;
public $secondField;
}
Dzięki
php
oop
coding-style
znak
źródło
źródło
Odpowiedzi:
Możesz użyć magicznych metod php
__get
i__set
.źródło
__get
i__set
. Istnieją dwa podkreślenia, a nie jedno. Oto bezpośredni link do prawej części strony: php.net/manual/en/… (+1 za poprawną odpowiedź)public
właściwości, jeśli nie ma walidacji / warunków sanitarnych?Dlaczego warto korzystać z getterów i seterów?
źródło
Google opublikował już przewodnik na temat optymalizacji PHP, a wniosek był następujący:
Bez gettera i setera Optymalizacja PHP
I nie, nie wolno ci używać magicznych metod . Dla PHP metoda magiczna jest zła. Czemu?
PHP nie jest Java, C ++ ani C #. PHP jest inny i gra różnymi rolami.
źródło
$dog->name = 'fido'
jest lepsze niż$dog->setName('fido')
. Podczas faktycznej mutacji właściwości (np.$dog->increaseAge(1)
Potrafię opracować metodę, która dokonuje niezbędnej walidacji i mutuje tę właściwość. Ale nie wszystkie działania naprawdę wymagają mutacji w tym sensieKapsułkowanie jest ważne w każdym języku OO, popularność nie ma z tym nic wspólnego. W dynamicznie wpisywanych językach, takich jak PHP, jest to szczególnie przydatne, ponieważ istnieje niewiele sposobów, aby upewnić się, że właściwość jest określonego typu bez użycia seterów.
W PHP działa to:
W Javie nie:
Korzystanie z magicznych metod (
__get
i__set
) również działa, ale tylko podczas uzyskiwania dostępu do właściwości, która ma mniejszą widoczność niż obecny zakres może uzyskać. Może z łatwością wywoływać bóle głowy podczas próby debugowania, jeśli nie jest właściwie używany.źródło
$bar
jakoint
w pierwszym przykładzie: wiki.php.net/rfc/typed_properties_v2Jeśli wolisz korzystać z funkcji __call, możesz użyć tej metody. Działa z
$this->property()
$this->property($value)
$this->getProperty()
$this->setProperty($value)
kalsdas
źródło
property_exists(get_class($this), $name)
a rekurencja jest powolna. Istnieje sposób na złagodzenie tego za pomocą buforowania, ale nadal będzie on wolniejszy niż ręczne tworzenie getterów i seterów. Napisałem to tylko jako alternatywę. Właściwie nie polecam używania „Magicznych metod”. Dodatkowy czas tworzenia getterów i seterów jest zwykle nieistotny.Oprócz świetnych i szanowanych odpowiedzi tutaj chciałbym rozwinąć PHP bez żadnych setterów / getterów.
PHP nie ma składni gettera i settera . Zapewnia podklasowe lub magiczne metody umożliwiające „zaczepienie” i przesłonięcie procesu wyszukiwania właściwości, jak zauważył Dave .
Magic pozwala nam leniwym programistom robić więcej przy mniejszym kodzie w czasie, gdy jesteśmy aktywnie zaangażowani w projekt i znamy go dokładnie, ale zwykle kosztem czytelności.
Wydajność Każda niepotrzebna funkcja, która wynika z wymuszenia architektury kodu przypominającej getter / setter w PHP, obejmuje własną ramkę stosu pamięci podczas wywoływania i marnuje cykle procesora.
Czytelność: podstawa kodu powoduje wzdęcie linii kodu, co wpływa na nawigację po kodzie, ponieważ więcej LOC oznacza więcej przewijania.
Preferencje: Osobiście, zgodnie z moją ogólną zasadą, traktuję niepowodzenie analizy kodu statycznego jako znak, aby uniknąć pójścia magiczną drogą, o ile w tym czasie wymykają mi się oczywiste długoterminowe korzyści.
Błędy:
Częstym argumentem jest czytelność. Na przykład
$someobject->width
jest to łatwiejsze do odczytania niż$someobject->width()
. Jednak w odróżnieniu od planetycircumference
lubwidth
, jak można to założyćstatic
, instancji obiektu, takiej jak$someobject
, która wymaga funkcji szerokości, prawdopodobnie mierzy szerokość instancji obiektu.Dlatego czytelność zwiększa się głównie z powodu asertywnych schematów nazewnictwa, a nie przez ukrycie funkcji, która generuje daną wartość właściwości.
__get / __set używa:
wstępna walidacja i wstępna dezynfekcja wartości nieruchomości
struny np
W takim przypadku
generatelatex
zastosowałby się schemat nazewnictwa akcji nazwa + nazwa metodyspecjalne, oczywiste przypadki
Uwaga: PHP zdecydowało się nie implementować składni getter / setter. Nie twierdzę, że osoby pobierające / ustawiające są ogólnie złe.
źródło
Gotowy!
źródło
Cóż, PHP ma magicznych sposobów
__get
,__set
,__isset
i__unset
, co jest zawsze początek. Niestety właściwe (rozumiesz?) Właściwości OO to coś więcej niż metody magiczne. Główny problem z implementacją PHP polega na tym, że wywoływane są magiczne metody dla wszystkich niedostępnych właściwości. Co oznacza, że musisz powtórzyć się (np. Wywołując property_exists ()) w magicznych metodach podczas określania, czy imię jest faktycznie własnością twojego obiektu. I tak naprawdę nie możesz rozwiązać tego ogólnego problemu z klasą podstawową, chyba że wszystkie twoje klasy dziedziczą np. ClassWithProperties, ponieważ PHP nie ma wielokrotnego dziedziczenia.W przeciwieństwie do tego, nowe klasy stylu Pythona dają ci
property()
możliwość jawnego zdefiniowania wszystkich swoich właściwości. C # ma specjalną składnię.http://en.wikipedia.org/wiki/Property_(programming)
źródło
Zrobiłem eksperyment przy użyciu magicznej metody __call. Nie jestem pewien, czy powinienem to opublikować (z powodu wszystkich ostrzeżeń „NIE UŻYWAJ METOD MAGICZNYCH” w innych odpowiedziach i komentarzach), ale zostawię to tutaj… na wypadek, gdyby ktoś uznał to za przydatne.
Po prostu dodaj tę metodę powyżej w swojej klasie, teraz możesz wpisać:
W ten sposób możesz pobrać / ustawić wszystko w swojej klasie, jeśli istnieje, więc jeśli potrzebujesz go tylko dla kilku konkretnych elementów, możesz użyć „białej listy” jako filtra.
Przykład:
Teraz możesz tylko ustawić / ustawić „foo” i „opłata”.
Możesz także użyć tej „białej listy”, aby przypisać niestandardowe nazwy dostępu do swoich zmiennych.
Na przykład,
Na tej liście możesz teraz wpisać:
.
.
.
To wszystko.
Doc: __call () jest wyzwalany podczas wywoływania niedostępnych metod w kontekście obiektowym.
źródło
Po przeczytaniu innych rad mam skłonność powiedzieć, że:
Jako GENERIC reguły nie zawsze określają ustawiające dla WSZYSTKICH właściwości, szczególnie te „wewnętrzne” (semafory, wewnętrzne flagi ...). Oczywiście właściwości tylko do odczytu nie będą miały ustawiających, więc niektóre właściwości będą miały tylko ustawiające; tam właśnie przychodzi __get (), aby zmniejszyć kod:
Tak! moglibyśmy napisać prywatną metodę, aby to zrobić, ale wtedy znowu będziemy WIELU metod zadeklarowanych (pamięć ++), które w końcu wywołują inną, zawsze tę samą, metodę. Dlaczego nie napisać POJEDYNCZEJ metody, by rządzić nimi wszystkimi ...? [tak! kalambur absolutnie przeznaczony! :)]
Ustawiacze magii mogą również reagować TYLKO na określone właściwości, więc wszystkie właściwości typu daty mogą być sprawdzane pod kątem nieprawidłowych wartości tylko w jednej metodzie. Jeśli właściwości typu daty były wymienione w tablicy, ich ustawiacze można łatwo zdefiniować. Oczywiście tylko przykład. jest zbyt wiele sytuacji.
O czytelności ... Cóż ... To kolejna debata: Nie lubię być związana z użyciem IDE (w rzeczywistości nie używam ich, zwykle mówią mi (i zmuszają ) jak pisz ... a ja lubię kodować „piękno”). Zwykle jestem konsekwentny w nazywaniu, więc używanie tagów i kilku innych pomocy jest dla mnie wystarczające ... W każdym razie: kiedy wszystkie te magiczne setery i gettery są skończone, piszę inne sety, które są zbyt specyficzne lub „specjalne”, aby być uogólnione w metodzie __set (). I to wszystko, czego potrzebuję, aby uzyskać i ustawić właściwości. Oczywiście: nie zawsze istnieje wspólna płaszczyzna lub istnieje kilka takich właściwości, które nie są warte kłopotu z kodowaniem magicznej metody, a ponadto istnieje stara, dobra, tradycyjna para setter / getter.
Języki programowania są po prostu: sztuczne języki ludzkie. Każdy z nich ma swoją intonację lub akcent, składnię i smak, więc nie będę udawał, że piszę kod Ruby lub Python przy użyciu tego samego „akcentu” niż Java lub C #, ani nie napisałbym JavaScript ani PHP, aby przypominać Perl lub SQL ... Używaj ich tak, jak powinny.
źródło
Ogólnie rzecz biorąc, pierwszy sposób jest ogólnie bardziej popularny, ponieważ osoby posiadające wcześniejszą wiedzę programistyczną mogą łatwo przejść na PHP i wykonywać pracę w sposób obiektowy. Pierwszy sposób jest bardziej uniwersalny. Radzę trzymać się tego, co sprawdzone i sprawdzone w wielu językach. Następnie, gdy używasz innego języka, będziesz gotowy, aby coś osiągnąć ( zamiast spędzać czas na nowo wymyślając koło ).
źródło
Istnieje wiele sposobów tworzenia kodu źródłowego w konwencji netbeans. To jest miłe. Ułatwia to myślenie === FAŁSZ. Po prostu skorzystaj z tradycji, zwłaszcza jeśli nie masz pewności, która z właściwości powinna zostać zamknięta, a która nie. Wiem, to jest kod boi .... pla ..., ale do debugowania działa i wiele innych uważa, że jest to lepszy, wyraźniejszy sposób. Nie spędzaj zbyt wiele czasu z tysiącami sztuk, jak robić proste gettery i setery. Nie możesz zaimplementować niektórych wzorców projektowych, takich jak zasada demeter i tak dalej, jeśli używasz magii. W konkretnej sytuacji możesz użyć magic_calls lub małych, szybkich i przejrzystych rozwiązań. Na pewno możesz w ten sposób tworzyć rozwiązania dla wzorników projektowych, ale po co utrudniać ci życie.
źródło
Sprawdzanie poprawności + formatowanie / wyprowadzanie wartości
Settery umożliwiają sprawdzanie poprawności danych, a gettery umożliwiają formatowanie lub uzyskiwanie danych. Obiekty umożliwiają enkapsulację danych oraz ich walidację i formatowanie kodu w zgrabny pakiet, który zachęca do OSUSZANIA.
Rozważmy na przykład następującą prostą klasę, która zawiera datę urodzenia.
Będziesz chciał sprawdzić, czy ustawiana jest wartość
I nie chcesz przeprowadzać tej weryfikacji w całej aplikacji (lub w wielu aplikacjach). Zamiast tego łatwiej jest ustawić zmienną członkowską jako chronioną lub prywatną (aby setter był jedynym punktem dostępu) i sprawdzić poprawność w seterze, ponieważ wtedy będziesz wiedział, że obiekt zawiera prawidłową datę urodzenia bez względu na to, która część aplikacja, z której pochodzi obiekt, a jeśli chcesz dodać więcej walidacji, możesz dodać ją w jednym miejscu.
Może chcesz dodać wiele formatek, które działają na tej samej zmiennej, tj członek
getAge()
igetDaysUntilBirthday()
, a może chcesz wymusić konfigurowalny format, wgetBirthDate()
zależności od kraju. Dlatego wolę konsekwentnie uzyskiwać dostęp do wartości za pośrednictwem metod pobierających zamiast mieszać się$date->getAge()
z$date->birth_date
.metody pobierające i ustawiające są również przydatne podczas rozszerzania obiektów. Załóżmy na przykład, że Twoja aplikacja musiała pozwalać na ponad 150-letnie daty urodzenia w niektórych miejscach, ale w innych nie. Jednym ze sposobów rozwiązania problemu bez powtarzania jakiegokolwiek kodu byłoby rozszerzenie
BirthDate
obiektu i umieszczenie dodatkowej weryfikacji w seterze.źródło
setHired
isetHireDate
. Nie jest dozwolone, aby ktoś ustalał datę zatrudnienia bez ustawiania pracownika jako zatrudnionego. Ale nie ma mowy, żebyś to egzekwował. Jeśli wymusisz to w jednym z tych ustawień, wówczas wymuszasz kolejność „ustawiania”, a to wymaga więcej odczytu kodu od programisty. Następnie, gdy przejdziesz do wykonania metody takiej jak$employee->promote($newPosition);
musisz sprawdzić flagę, aby sprawdzić, czy sprawdzanie poprawności zostało wykonane, lub załóż, że nie zostało to zrobione, i zrób to ponownie (nadmiarowe).$employee->updateWorkStatus($hired, $hireDate);
lub bardziej zaawansowany$employee->adminUpdate(\Employee\AdminUpdateDTO $dto);
. Teraz możesz sprawdzić poprawność w odpowiednim kontekście i zdecydować, czy w ogóle potrzebna jest dodatkowa weryfikacja.Ten post nie jest konkretnie o
__get
a__set
raczej__call
który jest taki sam pomysł z wyjątkiem metody powołania. Z reguły trzymam się z daleka od wszelkiego rodzaju magicznych metod, które pozwalają na przeładowanie z powodów opisanych w komentarzach i postach, JEDNAK ostatnio natknąłem się na interfejs API innej firmy, którego używam, który korzysta z usługi SERVICE i SUB-SERVICE, na przykład :Ważną częścią tego jest to, że ten interfejs API ma w tym przypadku wszystko to samo oprócz poddziałania
doActionOne
. Chodzi o to, że programista (ja i inni korzystający z tej klasy) może wywołać pod-usługę z nazwy, w przeciwieństwie do czegoś takiego:Mógłbym zamiast tego:
W przypadku kodu twardego byłoby to po prostu dużo powielania (ten przykład bardzo luźno przypomina kod):
Ale dzięki magicznej metodzie
__call()
jestem w stanie uzyskać dostęp do wszystkich usług za pomocą metod dynamicznych:Zaletą tego dynamicznego wezwania do zwrotu danych jest to, że jeśli dostawca doda inną pod-usługę, nie muszę dodawać innej metody do klasy ani tworzyć rozszerzonej klasy itp. Nie jestem pewien, czy jest to przydatne ktoś, ale pomyślałem, że pokażę przykład, w którym
__set
,__get
,__call
, itd. może być opcja do rozważenia, ponieważ podstawową funkcją jest powrót danych.EDYTOWAĆ:
Przypadkowo zobaczyłem to kilka dni po opublikowaniu, które dokładnie opisuje mój scenariusz. Nie chodzi o API, o którym mówiłem, ale zastosowanie metod jest identyczne:
Czy używam poprawnie interfejsu API?
źródło
Aktualizacja: nie używaj tej odpowiedzi, ponieważ jest to bardzo głupi kod, który znalazłem podczas nauki. Wystarczy użyć zwykłego gettera i setera, jest o wiele lepszy.
Zwykle używam tej nazwy zmiennej jako nazwy funkcji i dodam opcjonalny parametr do tej funkcji, więc gdy ten opcjonalny parametr zostanie wypełniony przez obiekt wywołujący, następnie ustaw go na właściwość i zwróć $ ten obiekt (łańcuch), a następnie, gdy ten opcjonalny parametr nie zostanie określony przez dzwoniącym, właśnie zwracam właściwość dzwoniącemu.
Mój przykład:
źródło