PHP to mój pierwszy język programowania. Nie mogę się do końca ogarnąć, kiedy używać klas statycznych, a kiedy obiektów utworzonych.
Zdaję sobie sprawę, że możesz powielać i klonować obiekty. Jednak przez cały mój czas używania php każdy obiekt lub funkcja zawsze kończyła się jako pojedyncza wartość zwracana (tablica, ciąg znaków, int) lub wartość void.
Rozumiem pojęcia z książek, takie jak klasa postaci z gier wideo. zduplikować obiekt samochodu i uczynić nowy czerwony , to wszystko ma sens, ale to, co nie jest, to jego zastosowanie w php i aplikacjach internetowych.
Prosty przykład. Blog. Jakie obiekty bloga najlepiej byłoby zaimplementować jako obiekty statyczne lub utworzone na podstawie instancji? Klasa DB? Dlaczego po prostu nie utworzyć instancji obiektu db w zakresie globalnym? Dlaczego zamiast tego uczynić każdy obiekt statycznym? A co z wydajnością?
Czy to tylko styl? Czy istnieje właściwy sposób na zrobienie tego?
Główne dwa powody przeciwko stosowaniu metod statycznych to:
Posiadanie statycznego wywołania metody wewnątrz innej metody jest w rzeczywistości gorsze niż importowanie zmiennej globalnej. W PHP klasy są symbolami globalnymi, więc za każdym razem, gdy wywołujesz metodę statyczną, polegasz na symbolu globalnym (nazwie klasy). Tak jest w przypadku, gdy globalność jest zła. Miałem problemy z takim podejściem z jakimś komponentem Zend Framework. Istnieją klasy, które używają statycznych wywołań metod (fabryk) do budowania obiektów. Nie mogłem dostarczyć innej fabryki do tej instancji w celu zwrotu dostosowanego obiektu. Rozwiązaniem tego problemu jest używanie tylko instancji i metod instancji oraz wymuszanie singletonów i tym podobnych na początku programu.
Miško Hevery , który pracuje jako Agile Coach w Google, ma ciekawą teorię, a raczej radzi, że powinniśmy oddzielić czas powstania obiektu od momentu jego użycia. Tak więc cykl życia programu jest podzielony na dwie części. Pierwsza część (
main()
powiedzmy metoda), która zajmuje się całym okablowaniem obiektów w Twojej aplikacji oraz częścią, która wykonuje rzeczywistą pracę.Więc zamiast mieć:
Powinniśmy raczej zrobić:
Następnie na stronie indeksu / głównej zrobilibyśmy (jest to krok okablowania obiektu lub czas na utworzenie wykresu instancji, które mają być używane przez program):
Głównym pomysłem jest oddzielenie zależności od twoich klas. W ten sposób kod jest znacznie bardziej rozszerzalny i, co dla mnie najważniejsze, testowalny. Dlaczego ważniejsze jest, aby być testowalnym? Ponieważ nie zawsze piszę kod biblioteki, więc rozszerzalność nie jest tak ważna, ale testowalność jest ważna podczas refaktoryzacji. W każdym razie, testowalny kod zazwyczaj daje rozszerzalny kod, więc tak naprawdę nie jest to sytuacja „albo-albo”.
Miško Hevery dokonuje również wyraźnego rozróżnienia między singletonami i singletonami (z wielką literą S lub bez niej). Różnica jest bardzo prosta. Singletony z małymi literami „s” są wymuszane przez okablowanie w indeksie / głównym. Tworzysz obiekt klasy, która nie implementuje wzorca Singleton, i dbasz o to, aby przekazać to wystąpienie tylko do każdej innej instancji, która tego potrzebuje. Z drugiej strony Singleton, przez duże „S” jest implementacją klasycznego (anty) wzorca. Zasadniczo globalny w przebraniu, który nie ma większego zastosowania w świecie PHP. Do tej pory żadnego nie widziałem. Jeśli chcesz, aby jedno połączenie DB było używane przez wszystkie Twoje klasy, lepiej zrób to w ten sposób:
Robiąc powyższe, widać wyraźnie, że mamy singletona i mamy też fajny sposób na wprowadzenie makiety lub kodu pośredniczącego w naszych testach. Zaskakujące jest, jak testy jednostkowe prowadzą do lepszego projektu. Ale ma to duży sens, gdy myślisz, że testy zmuszają cię do przemyślenia sposobu, w jaki użyjesz tego kodu.
Jedyną sytuacją, w której użyłbym (i użyłem ich do naśladowania obiektu prototypu JavaScript w PHP 5.3) statycznych elementów członkowskich, jest sytuacja, gdy wiem, że odpowiednie pole będzie miało tę samą wartość między instancjami. W tym momencie możesz użyć statycznej właściwości i być może pary statycznych metod pobierających / ustawiających. W każdym razie nie zapomnij dodać możliwości zastąpienia statycznego elementu członkowskiego elementem instancji. Na przykład Zend Framework używał statycznej właściwości w celu określenia nazwy klasy adaptera DB używanej w instancjach
Zend_Db_Table
. Minęło trochę czasu, odkąd ich używałem, więc może już nie mieć znaczenia, ale tak to pamiętam.Metody statyczne, które nie obsługują właściwości statycznych, powinny być funkcjami. PHP ma funkcje i powinniśmy ich używać.
źródło
Więc w PHP statyczne można zastosować do funkcji lub zmiennych. Zmienne niestatyczne są powiązane z konkretną instancją klasy. Metody niestatyczne działają na instancji klasy. Stwórzmy więc klasę o nazwie
BlogPost
.title
byłby elementem niestatycznym. Zawiera tytuł tego wpisu na blogu. Możemy również mieć metodę o nazwiefind_related()
. Nie jest statyczny, ponieważ wymaga informacji z określonej instancji klasy wpisu na blogu.Ta klasa wyglądałaby mniej więcej tak:
Z drugiej strony, używając funkcji statycznych, możesz napisać taką klasę:
W tym przypadku, ponieważ funkcja jest statyczna i nie działa na żadnym konkretnym poście na blogu, musisz przekazać wpis na blogu jako argument.
Zasadniczo jest to kwestia projektowania zorientowanego obiektowo. Twoje klasy to rzeczowniki w twoim systemie, a funkcje, które na nie działają, to czasowniki. Funkcje statyczne są proceduralne. Obiekt funkcji przekazujesz jako argumenty.
Aktualizacja: Dodałbym również, że rzadko podejmuje się decyzję między metodami instancji a metodami statycznymi, a bardziej między używaniem klas i użyciem tablic asocjacyjnych. Na przykład w aplikacji do blogowania albo czytasz posty na blogu z bazy danych i konwertujesz je na obiekty, albo zostawiasz je w zestawie wyników i traktujesz je jako tablice asocjacyjne. Następnie piszesz funkcje, które jako argumenty przyjmują tablice asocjacyjne lub listy tablic asocjacyjnych.
W scenariuszu OO piszesz w swojej
BlogPost
klasie metody, które działają na poszczególnych postach, i piszesz metody statyczne, które działają na kolekcjach postów.źródło
Tak, długa droga. Możesz pisać doskonale dobre programy obiektowe bez używania statycznych elementów członkowskich. W rzeczywistości niektórzy ludzie argumentowaliby, że statyczne elementy są przede wszystkim nieczystością. Sugerowałbym, aby - jako początkujący w oop - starać się unikać statycznych członków razem. Zmusi cię to do pisania w stylu obiektowym, a nie proceduralnym .
źródło
Mam tutaj inne podejście do większości odpowiedzi, zwłaszcza gdy używam PHP. Myślę, że wszystkie zajęcia powinny być statyczne, chyba że masz ku temu dobry powód. Oto niektóre z powodów „dlaczego nie”:
Podam jeden przykład. Ponieważ każdy skrypt PHP generuje kod HTML, mój framework ma klasę pisarza HTML. Zapewnia to, że żadna inna klasa nie będzie próbowała pisać kodu HTML, ponieważ jest to wyspecjalizowane zadanie, które powinno być skoncentrowane w jednej klasie.
Zwykle użyjesz klasy html w następujący sposób:
Za każdym razem, gdy wywoływana jest funkcja get_buffer (), resetuje ona wszystko, tak że następna klasa używająca programu zapisującego html zaczyna się w znanym stanie.
Wszystkie moje klasy statyczne mają funkcję init (), którą należy wywołać przed pierwszym użyciem tej klasy. Jest to bardziej umowne niż konieczność.
W tym przypadku alternatywa dla klasy statycznej jest nieuporządkowana. Nie chciałbyś, aby każda klasa, która musi napisać niewielką część kodu HTML, musiała zarządzać wystąpieniem programu piszącego HTML.
Teraz podam przykład, kiedy nie należy używać klas statycznych. Moja klasa formularza zarządza listą elementów formularza, takich jak dane wejściowe, listy rozwijane i nie tylko. Zwykle jest używany w następujący sposób:
Nie da się tego zrobić z klasami statycznymi, zwłaszcza biorąc pod uwagę, że niektórzy konstruktorzy każdej dodanej klasy wykonują dużo pracy. Ponadto łańcuch dziedziczenia dla wszystkich elementów jest dość złożony. Jest to więc wyraźny przykład, w którym nie należy używać klas statycznych.
Większość klas narzędziowych, takich jak te konwertujące / formatujące łańcuchy, jest dobrymi kandydatami do bycia klasą statyczną. Moja zasada jest prosta: wszystko jest statyczne w PHP, chyba że jest jeden powód, dla którego nie powinno.
źródło
„Posiadanie statycznego wywołania metody wewnątrz innej metody jest w rzeczywistości gorsze niż importowanie zmiennej globalnej”. (zdefiniuj „gorsze”) ... i „Metody statyczne, które nie mają do czynienia ze statycznymi właściwościami, powinny być funkcjami”.
Są to dość ogólne stwierdzenia. Jeśli mam zestaw funkcji powiązanych tematycznie, ale dane instancji są całkowicie nieodpowiednie, wolałbym, aby były zdefiniowane w klasie, a nie każda z nich w globalnej przestrzeni nazw. Po prostu używam mechaniki dostępnej w PHP5 do
jest to po prostu wygodny sposób na wymuszenie większej spójności i niższego sprzężenia.
I FWIW - nie ma czegoś takiego, przynajmniej w PHP5, jak „klasy statyczne”; metody i właściwości mogą być statyczne. Aby zapobiec tworzeniu instancji klasy, można również zadeklarować ją jako abstrakcyjną.
źródło
Najpierw zadaj sobie pytanie, co będzie reprezentować ten obiekt? Instancja obiektu jest dobra do działania na oddzielnych zestawach danych dynamicznych.
Dobrym przykładem może być ORM lub warstwa abstrakcji bazy danych. Możesz mieć wiele połączeń z bazą danych.
Te dwa połączenia mogą teraz działać niezależnie:
Teraz w tym pakiecie / bibliotece mogą istnieć inne klasy, takie jak Db_Row itp., Które reprezentują określony wiersz zwracany przez instrukcję SELECT. Gdyby ta klasa Db_Row była klasą statyczną, to przy założeniu, że masz tylko jeden wiersz danych w jednej bazie danych i niemożliwe byłoby zrobienie tego, co mogłaby zrobić instancja obiektu. Dzięki instancji możesz teraz mieć nieograniczoną liczbę wierszy w nieograniczonej liczbie tabel w nieograniczonej liczbie baz danych. Jedynym ograniczeniem jest sprzęt serwera;).
Na przykład, jeśli metoda getRows w obiekcie Db zwraca tablicę obiektów Db_Row, możesz teraz operować na każdym wierszu niezależnie od siebie:
Dobrym przykładem klasy statycznej może być coś, co obsługuje zmienne rejestrowe lub zmienne sesji, ponieważ będzie tylko jeden rejestr lub jedna sesja na użytkownika.
W jednej części aplikacji:
A w innej części:
Ponieważ na sesję będzie przypadał tylko jeden użytkownik na raz, nie ma sensu tworzyć instancji dla sesji.
Mam nadzieję, że wraz z innymi odpowiedziami pomoże to wyjaśnić. Na marginesie, sprawdź „ spójność ” i „ sprzężenie ”. Przedstawiają one bardzo, bardzo dobre praktyki do wykorzystania podczas pisania kodu, które mają zastosowanie do wszystkich języków programowania.
źródło
Jeśli twoja klasa jest statyczna, oznacza to, że nie możesz przekazać jej obiektu do innych klas (ponieważ nie ma możliwości wystąpienia instancji), więc oznacza to, że wszystkie twoje klasy będą bezpośrednio używać tej klasy statycznej, co oznacza, że twój kod jest teraz ściśle powiązany z klasą .
Ścisłe połączenie sprawia, że kod jest mniej przydatny do ponownego wykorzystania, kruchy i podatny na błędy. Chcesz uniknąć klas statycznych, aby móc przekazywać instancję klasy do innych klas.
I tak, to tylko jeden z wielu innych powodów, z których niektóre zostały już wspomniane.
źródło
Ogólnie rzecz biorąc, należy używać zmiennych składowych i funkcji składowych, chyba że jest to absolutnie konieczne dla wszystkich instancji lub jeśli tworzysz singleton. Korzystanie z danych składowych i funkcji składowych umożliwia ponowne wykorzystanie funkcji dla wielu różnych fragmentów danych, podczas gdy możesz mieć tylko jedną kopię danych, na których operujesz, jeśli używasz danych i funkcji statycznych. Dodatkowo, chociaż nie ma to zastosowania w PHP, statyczne funkcje i dane prowadzą do tego, że kod nie jest ponownie wprowadzany, podczas gdy dane klas ułatwiają ponowne wejście.
źródło
Chciałbym powiedzieć, że zdecydowanie istnieje przypadek, w którym chciałbym zmienne statyczne - w aplikacjach międzyjęzykowych. Możesz mieć klasę, do której przekazujesz język (np. $ _SESSION ['language']), a ona z kolei uzyskuje dostęp do innych klas zaprojektowanych w ten sposób:
Użycie Strings :: getString ("somestring") to dobry sposób na wyodrębnienie użycia języka z aplikacji. Możesz to zrobić w dowolny sposób, ale w tym przypadku posiadanie stałych z wartościami łańcuchowymi w każdym pliku łańcuchowym, do których ma dostęp klasa Strings, działa całkiem nieźle.
źródło