Wiem, że PHP nie ma natywnych wyliczeń. Ale przyzwyczaiłem się do nich ze świata Java. Chciałbym używać wyliczeń jako sposobu na podanie predefiniowanych wartości, które funkcje automatycznego uzupełniania IDE mogłyby zrozumieć.
Stałe załatwiają sprawę, ale istnieje problem kolizji przestrzeni nazw i (a właściwie dlatego, że) są globalne. Tablice nie mają problemu z przestrzenią nazw, ale są zbyt niejasne, można je nadpisać w czasie wykonywania, a IDE rzadko (nigdy?) Nie wiedzą, jak automatycznie wypełnić swoje klucze.
Czy są jakieś rozwiązania / obejścia, których często używasz? Czy ktoś pamięta, czy faceci PHP mieli jakieś przemyślenia lub decyzje dotyczące enum?
php
enumeration
Henrik Paul
źródło
źródło
Odpowiedzi:
W zależności od przypadku użycia zwykle użyłbym czegoś prostego, takiego jak:
Jednak inne przypadki użycia mogą wymagać większej weryfikacji stałych i wartości. W oparciu o poniższe komentarze na temat refleksji i kilka innych uwag , oto rozszerzony przykład, który może lepiej służyć w znacznie szerszym zakresie przypadków:
Tworząc prostą klasę enum, która rozszerza BasicEnum, możesz teraz w ten sposób używać metod do prostej weryfikacji danych wejściowych:
Na marginesie: za każdym razem, gdy przynajmniej raz użyję odbicia w klasie statycznej / stałej, w której dane się nie zmienią (np. W wyliczeniu), buforuję wyniki tych wywołań odbicia, ponieważ za każdym razem używam świeżych obiektów odbicia ostatecznie będzie miało zauważalny wpływ na wydajność (Przechowywane w tablicy asocjacyjnej dla wielu wyliczeń).
Teraz, gdy większość ludzi w końcu dokonała aktualizacji do wersji co najmniej 5.3 i
SplEnum
jest dostępna, jest to z pewnością realna opcja - pod warunkiem, że nie masz nic przeciwko tradycyjnie nieintuicyjnemu wyobrażeniu o tworzeniu instancji w enum w całej bazie kodu. W powyższym przykładzie,BasicEnum
iDaysOfWeek
nie może być instancja w ogóle, ani nie powinny być.źródło
abstract
ifinal
tak nie może być instancja lub przekształcone.abstract
ifinal
? Wiem, że w Javie jest to niedozwolone. Możesz to zrobić w php?abstract
ifinal
. W takim razie wybrałbym streszczenie.null
i przyjaciółmi wswitch
wypowiedzi. Byłem tamIstnieje również rozszerzenie natywne. SplEnum
http://www.php.net/manual/en/class.splenum.php
Uwaga:
https://www.php.net/manual/en/spl-types.installation.php
źródło
Co ze stałymi klasowymi?
źródło
echoConstant
można zastąpić__toString
. A potem po prostuecho $c
Górna odpowiedź powyżej jest fantastyczna. Jeśli jednak zrobisz
extend
to na dwa różne sposoby, w zależności od tego, które rozszerzenie zostanie wykonane jako pierwsze, wywołanie funkcji utworzy pamięć podręczną. Ta pamięć podręczna będzie następnie używana przez wszystkie kolejne połączenia, niezależnie od rozszerzenia, które połączenia są inicjowane przez ...Aby rozwiązać ten problem, zamień zmienną i pierwszą funkcję na:
źródło
Użyłem klas ze stałymi:
źródło
Używam
interface
zamiastclass
:źródło
class Foo implements DaysOfWeek { }
a potemFoo::Sunday
... co?class
(lubinterface
, co jest tylko kwestią preferencji).Skomentowałem niektóre inne odpowiedzi tutaj, więc pomyślałem, że też waży. Ostatecznie, ponieważ PHP nie obsługuje wyliczeń wpisywanych na klawiaturze, możesz przejść na jeden z dwóch sposobów: zhakować wyliczenia wpisane na maszynie lub żyć z faktem, że niezwykle trudno jest je skutecznie wyhackować.
Wolę żyć z tym faktem i zamiast tego użyć
const
metody, którą w inny sposób zastosowały inne odpowiedzi tutaj:Przykładowe wyliczenie:
Użycie
Enum
jako klasy podstawowej, z której rozciągają się wszystkie inne wyliczenia, pozwala na zastosowanie metod pomocniczych, takich jaktoArray
,isValid
itd. Dla mnie wpisane wyliczenia ( i zarządzanie ich instancjami ) są po prostu zbyt niechlujne.Hipotetyczny
Jeśli istniała
__getStatic
metoda magiczna ( najlepiej też__equals
magiczna) ), wiele z nich można by złagodzić za pomocą pewnego rodzaju wzoru wielotonowego.( Poniższe jest hipotetyczne; nie zadziała, choć może kiedyś to nastąpi )
źródło
Cóż, dla prostego java takiego jak enum w php używam:
I nazwać to:
Ale jestem początkującym PHP i mam problemy ze składnią, więc może to nie być najlepszy sposób. Poeksperymentowałem ze stałymi klasowymi, użycie Odbicia, aby uzyskać stałą nazwę z jej wartości, może być fajniejsze.
źródło
Cztery lata później znów się z tym spotkałem. Moje obecne podejście jest takie, ponieważ pozwala na uzupełnianie kodu w IDE, a także na bezpieczeństwo typu:
Klasa podstawowa:
Przykład wyliczenia:
Przykładowe użycie:
Zauważ, że wszystkie wystąpienia tego samego wpisu wyliczeniowego są takie same:
Możesz również użyć go w instrukcji switch:
Możesz także utworzyć pozycję enum według nazwy lub wartości:
Lub możesz po prostu uzyskać nazwę (tj. Nazwę funkcji) z istniejącego wpisu wyliczeniowego:
źródło
const Monday = DaysOfWeek('Monday');
Znalazłem tę bibliotekę na githubie i myślę, że stanowi ona bardzo przyzwoitą alternatywę dla odpowiedzi tutaj.
Implementacja PHP Enum inspirowana SplEnum
function setAction(Action $action) {
format
,parse
...)final
aby temu zapobiec)Deklaracja
Stosowanie
wartości wyliczenia podpowiedzi typu:
źródło
enum
zostanie dodana w PHP 7.x), ponieważ pozwala na podpowiedzi typu.__toString()
magię pozwala ci robić to, co na ogół naprawdę chcesz z wyliczeniami - używaj ich w instrukcjiswitch
lubif
, porównując bezpośrednio z wartościami const. Najlepsze podejście poza natywną obsługą enum, IMO.Jeśli potrzebujesz użyć wyliczeń, które są globalnie unikalne (tj. Nawet przy porównywaniu elementów między różnymi wyliczeniami) i są łatwe w użyciu, możesz użyć następującego kodu. Dodałem także kilka metod, które uważam za przydatne. Przykłady znajdziesz w komentarzach na samej górze kodu.
źródło
eval()
tylko w celu zadeklarowania nowego środowiska uruchomieniowego Enums? Eek. Nie czuje tego Jak zapobiec tworzeniu przez inne klasy niepoprawnej klasy Enum przed zdefiniowaniem właściwej? Czy Enums nie są znane przed uruchomieniem? I jak sugeruje @corsiKa, brak autouzupełniania IDE. Jedyną korzyścią, jaką widzę, jest leniwe kodowanie.Lubię też wyliczenia z java iz tego powodu piszę wyliczenia w ten sposób, myślę, że jest to najbardziej podobne zachowanie jak w wyliczeniach Java, oczywiście, jeśli ktoś chce użyć więcej metod z java, powinien napisać to tutaj, lub w klasa abstrakcyjna, ale podstawowa idea jest osadzona w kodzie poniżej
źródło
FruitsEnum::Apple()
ponadFruitsEnum::$Apple
, ale ważniejszy powód jest zapobieganie nikogo innego z ustawieniem$APPLE
, łamiąc w ten sposób wyliczenia dla całej aplikacji. Drugi to prosta prywatna flaga statyczna$initialized
, którainit()
gwarantuje , że wywołanie nie będzie działać po pierwszym wywołaniu (więc nikt też nie może z tym zadzierać)..init()
jest dziwne i nie przeszkadza mi podejście gettera.źródło
To może być tak proste jak
w przyszłości.
PHP RFC: typy wyliczone
źródło
Najczęstszym rozwiązaniem, które widziałem dla enum w PHP, było utworzenie ogólnej klasy enum, a następnie jej rozszerzenie. Można spojrzeć na to .
AKTUALIZACJA: Alternatywnie znalazłem to z phpclasses.org.
źródło
Oto biblioteka github do obsługi wyliczeń bezpiecznych dla typu w php:
Ta biblioteka obsługuje generowanie klas, buforowanie klas i implementuje wzorzec projektowy Bezpieczne wyliczanie typów, z kilkoma metodami pomocniczymi do radzenia sobie z wyliczeniami, takimi jak wyszukiwanie porządków do sortowania wyliczeń lub pobieranie wartości binarnych dla kombinacji wyliczeń.
Wygenerowany kod używa zwykłego starego pliku szablonu php, który można również konfigurować, dzięki czemu możesz podać własny szablon.
Jest to pełny test pokryty phpunitem.
php-enums na github (nie krępuj się rozwidlać)
Użycie: (@see use.php lub testy jednostkowe, aby uzyskać więcej informacji)
Wynik:
źródło
Zastosowałem poniższe podejście, ponieważ daje mi ono możliwość zapewnienia bezpieczeństwa typu dla parametrów funkcji, automatycznego uzupełniania w NetBeans i dobrej wydajności. Jedyne, co mi się nie podoba, to to, że musisz zadzwonić
[extended class name]::enumerate();
po zdefiniowaniu klasy.źródło
DaysOfWeek::$MONDAY = 3;
[extended class name]::enumerate();
po definicji, dlaczego nie robisz tego w konstrukcie?Moja definicja klasy Enum poniżej jest silnie wpisana i bardzo naturalna w użyciu i zdefiniowaniu.
Definicja:
Przełącz Enum
Przekaż Enum jako parametr (silnie wpisany)
Echo Enum jako ciąg
Uzyskaj Enum przez liczbę całkowitą
Uzyskaj Enum według nazwy
Klasa Enum:
Dodanie
Możesz oczywiście dodawać komentarze do IDE
źródło
Zdaję sobie sprawę, że to bardzo, bardzo, bardzo stary wątek, ale pomyślałem o tym i chciałem wiedzieć, co myślą ludzie.
Uwagi: bawiłem się tym i zdałem sobie sprawę, że jeśli po prostu zmodyfikuję
__call()
funkcję, możesz zbliżyć się do rzeczywistościenums
.__call()
Funkcja obsługuje wszystkie nieznane połączenia funkcji. Powiedzmy, że chcesz zrobić trzyenums
RED_LIGHT, YELLOW_LIGHT i GREEN_LIGHT. Możesz to zrobić teraz, wykonując następujące czynności:Po zdefiniowaniu wystarczy zadzwonić do nich ponownie, aby uzyskać wartości:
i powinieneś dostać 0, 1 i 2. Baw się dobrze! To jest teraz także dostępne w GitHub.
Aktualizacja: Zrobiłem to, więc teraz są używane funkcje
__get()
i__set()
. Pozwalają ci one nie musieć wywoływać funkcji, chyba że chcesz. Zamiast tego możesz teraz powiedzieć:Zarówno do tworzenia, jak i uzyskiwania wartości. Ponieważ zmienne nie zostały początkowo zdefiniowane,
__get()
funkcja jest wywoływana (ponieważ nie określono wartości), co oznacza, że wpis w tablicy nie został wprowadzony. Czyni zatem wpis, przypisuje mu ostatnią podaną wartość plus jeden (+1), zwiększa ostatnią zmienną wartości i zwraca PRAWDA. Jeśli ustawisz wartość:Następnie
__set()
wywoływana jest funkcja, a ostatnia wartość jest ustawiana na nową wartość plus jeden (+1). Więc teraz mamy dość dobry sposób na wyliczanie i można je tworzyć w locie.źródło
Wiem, że jest to stary wątek, jednak żadne z obejść, które widziałem, nie wyglądało naprawdę jak wyliczenia, ponieważ prawie wszystkie obejścia wymagają ręcznego przypisania wartości do elementów wyliczeniowych, lub wymagają przekazania tablicy kluczy wyliczeniowych do funkcjonować. Więc stworzyłem własne rozwiązanie.
Aby utworzyć klasę enum przy użyciu mojego rozwiązania, wystarczy po prostu rozszerzyć tę klasę Enum poniżej, utworzyć wiązkę zmiennych statycznych (nie trzeba ich inicjować) i wywołać metodę yourEnumClass :: init () tuż poniżej definicji klasy enum .
edit: Działa to tylko w php> = 5.3, ale prawdopodobnie można go zmodyfikować tak, aby działał również w starszych wersjach
źródło
Teraz możesz użyć klasy SplEnum, aby zbudować ją natywnie. Zgodnie z oficjalną dokumentacją.
Uwaga: jest to rozszerzenie, które musi być zainstalowane, ale domyślnie niedostępne. Który znajduje się w sekcji Typy specjalne opisane w samej witrynie php. Powyższy przykład pochodzi ze strony PHP.
źródło
Na koniec odpowiedź PHP 7.1+ ze stałymi, których nie można zastąpić.
Jeśli używasz przestrzeni nazw, uzupełnianie kodu powinno działać.
Jednak robiąc to, tracisz możliwość ukrywania stałych w rodzinie klas (
protected
) lub samej klasie (private
). Z definicji wszystkoInterface
jest wpublic
.Podręcznik PHP: Interfejsy
źródło
To jest moje zdanie na temat „dynamicznego” wyliczenia ... abym mógł go nazwać zmiennymi, np. z formularza.
spójrz na zaktualizowaną wersję poniżej tego kodu ...
AKTUALIZACJA: Lepszy sposób na zrobienie tego ...
Zadzwoń z
źródło
EnumCategory::$sport = 9;
. Witamy w muzeum sportu.const
jest lepszym sposobem na zrobienie tego.Przyjęta odpowiedź jest właściwą drogą i tak naprawdę robię to dla uproszczenia. Oferowane są większość zalet wyliczenia (czytelne, szybkie itp.). Brakuje jednak jednej koncepcji: bezpieczeństwo typu. W większości języków wyliczenia są również używane do ograniczenia dozwolonych wartości. Poniżej znajduje się przykład, w jaki sposób można uzyskać bezpieczeństwo typu przy użyciu prywatnych konstruktorów, metod tworzenia instancji statycznych i sprawdzania typu:
Możemy nawet pójść dalej: użycie stałych w klasie DaysOfWeek może prowadzić do niewłaściwego użycia: np. Można błędnie użyć tego w ten sposób:
co jest złe (wywołuje stałą całkowitą). Możemy temu zapobiec za pomocą prywatnych zmiennych statycznych zamiast stałych:
Oczywiście nie jest możliwy dostęp do stałych całkowitych (taki był właśnie cel). Metoda intVal pozwala na konwersję obiektu DaysOfWeek na jego całkowitą reprezentację.
Zauważ, że moglibyśmy nawet pójść dalej, wdrażając mechanizm buforowania w metodach tworzenia instancji w celu zaoszczędzenia pamięci w przypadku, gdy wyliczenia są szeroko stosowane ...
Mam nadzieję, że to pomoże
źródło
Kilka dobrych rozwiązań tutaj!
Oto moja wersja.
Myślę, że główną wadą jest to, że członkowie enum muszą być osobno zadeklarowani i utworzeni instancji, ze względu na opisy i niezdolność PHP do konstruowania obiektów w czasie statycznej deklaracji członka. Myślę, że rozwiązaniem może być użycie refleksji z parsowanymi komentarzami doktorów.
Abstrakcyjne wyliczenie wygląda następująco:
Oto przykład konkretnego wyliczenia:
Które można wykorzystać w ten sposób:
I produkuje ten wynik:
źródło
Nie używaj refleksji. Utrudnia to rozumowanie twojego kodu i śledzenie, gdzie coś jest używane, i ma tendencję do niszczenia narzędzi do analizy statycznej (np. Tego, co jest wbudowane w twoje IDE).
źródło
Jednym z aspektów, których brakuje w niektórych innych odpowiedziach tutaj, jest sposób użycia wyliczeń z podpowiedziami typu.
Jeśli zdefiniujesz swój wyliczenie jako zbiór stałych w klasie abstrakcyjnej, np
to nie można wpisać schować go w parametrze funkcji - dla jednego, bo to nie jest chwilowe, ale także dlatego, że typ
ShirtSize::SMALL
jestint
, nieShirtSize
.Dlatego natywne wyliczenia w PHP byłyby o wiele lepsze niż cokolwiek, co możemy wymyślić. Możemy jednak zbliżyć wyliczenie, zachowując własność prywatną, która reprezentuje wartość wyliczenia, a następnie ograniczając inicjalizację tej właściwości do naszych predefiniowanych stałych. Aby zapobiec arbitralnej instancji wyliczenia (bez konieczności sprawdzania białej listy), konstruktor staje się prywatny.
Następnie możemy użyć w
ShirtSize
następujący sposób:W ten sposób największą różnicą z punktu widzenia użytkownika jest to, że musisz przyczepić się do
()
nazwy stałej.Jedną wadą jest to, że
===
(która porównuje równość obiektów) zwróci false, gdy==
zwróci true. Z tego powodu najlepiej jest podaćequals
metodę, aby użytkownicy nie musieli pamiętać o używaniu==
i===
nieporównywaniu dwóch wartości wyliczeniowych.EDYCJA: Kilka istniejących odpowiedzi jest bardzo podobnych, w szczególności: https://stackoverflow.com/a/25526473/2407870 .
źródło
Opierając się na odpowiedzi @Brian Cline, pomyślałem, że mogę dać moje 5 centów
źródło
include('enums.php');
]. Z jakiegoś powodu nie widzi funkcji zadeklarowanych w Enum dla klas potomnych ...$currentSeason.set("Spring");
Moja próba utworzenia wyliczenia za pomocą PHP ... jest bardzo ograniczona, ponieważ nie obsługuje obiektów jako wartości wyliczeniowych, ale wciąż jest trochę przydatna ...
źródło
Wczoraj napisałem tę klasę na swoim blogu . Myślę, że może być łatwy w użyciu w skryptach php:
Stosowanie:
źródło