Eu sei que o PHP não tem enumerações nativas. Mas eu me acostumei a eles do mundo Java. Eu adoraria usar enums como uma maneira de fornecer valores predefinidos que os recursos de preenchimento automático dos IDEs pudessem entender.
As constantes fazem o truque, mas há o problema de colisão de namespace e (ou na verdade porque ) são globais. As matrizes não têm o problema do espaço para nome, mas são muito vagas, podem ser substituídas em tempo de execução e os IDEs raramente (nunca?) Sabem como preencher automaticamente suas chaves.
Existem soluções / soluções alternativas que você costuma usar? Alguém se lembra se os caras do PHP tiveram alguma opinião ou decisão sobre enums?
php
enumeration
Henrik Paul
fonte
fonte
Respostas:
Dependendo do caso de uso, normalmente eu usaria algo simples como o seguinte:
No entanto, outros casos de uso podem exigir mais validação de constantes e valores. Com base nos comentários abaixo sobre reflexão e em algumas outras notas , aqui está um exemplo expandido que pode atender melhor a uma variedade muito maior de casos:
Ao criar uma classe enum simples que estende o BasicEnum, agora você tem a capacidade de usar métodos para validação de entrada simples:
Como observação lateral, sempre que eu usar reflexão pelo menos uma vez em uma classe static / const em que os dados não serão alterados (como em uma enumeração), eu armazeno em cache os resultados dessas chamadas de reflexão, desde que você use objetos de reflexão sempre atualizados acabará por ter um impacto perceptível no desempenho (armazenado em uma matriz associativa para várias enumerações).
Agora que a maioria das pessoas finalmente atualizou para pelo menos 5,3 e
SplEnum
está disponível, essa também é uma opção viável - desde que você não se importe com a noção tradicionalmente não intuitiva de ter instanciações enum reais em toda a sua base de código. No exemplo acima,BasicEnum
eDaysOfWeek
não pode ser instanciado, nem deveria ser.fonte
abstract
efinal
, portanto, não pode ser instanciada ou estendida.abstract
efinal
? Eu sei que em Java isso não é permitido. Você pode fazer isso em php?abstract
efinal
. Nesse caso, eu procuraria por resumo.null
e amigos em umaswitch
declaração. Esteve lá.Também há uma extensão nativa. O SplEnum
http://www.php.net/manual/en/class.splenum.php
Atenção:
https://www.php.net/manual/en/spl-types.installation.php
fonte
E as constantes de classe?
fonte
echoConstant
pode ser substituído por__toString
. E então simplesmenteecho $c
A resposta superior acima é fantástica. No entanto, se você
extend
isso de duas maneiras diferentes, qualquer extensão feita primeiro resultará em uma chamada para as funções criará o cache. Esse cache será usado por todas as chamadas subsequentes, independentemente do ramal que as chamadas sejam iniciadas por ...Para resolver isso, substitua a variável e a primeira função por:
fonte
Eu usei classes com constantes:
fonte
Eu uso em
interface
vez declass
:fonte
class Foo implements DaysOfWeek { }
e entãoFoo::Sunday
... o que?class
(ouinterface
, que é apenas uma questão de preferência).Eu comentei algumas das outras respostas aqui, então achei que também pesaria. No final do dia, como o PHP não suporta enumerações digitadas, você pode seguir um de dois modos: hackear enumerações digitadas ou viver com o fato de que são extremamente difíceis de hackear efetivamente.
Eu prefiro viver com o fato e, em vez disso, use o
const
método que outras respostas aqui usaram de uma maneira ou de outra:Um exemplo de enumeração:
Usando
Enum
como uma classe de base a partir do qual todos os outros enumerações estender permite métodos auxiliares, tais comotoArray
,isValid
e assim por diante. Para mim, as enumerações digitadas ( e o gerenciamento de suas instâncias ) acabam muito confusas.Hipotético
Se existisse um
__getStatic
método mágico ( e de preferência um__equals
método mágico também ), muito disso poderia ser mitigado com uma espécie de padrão multiton.( O seguinte é hipotético; não funcionará, embora talvez um dia funcione )
fonte
Bem, para um java simples como o enum no php, eu uso:
E para chamá-lo:
Mas eu sou iniciante em PHP, lutando com a sintaxe, então essa pode não ser a melhor maneira. Eu experimentei algumas com constantes de classe, usando Reflection para obter o nome constante de seu valor, pode ser mais limpo.
fonte
Quatro anos depois, me deparei com isso novamente. Minha abordagem atual é essa, pois permite a conclusão do código no IDE, bem como o tipo de segurança:
Classe base:
Exemplo Enum:
Exemplo de uso:
Observe que todas as instâncias da mesma entrada enum são as mesmas:
Você também pode usá-lo dentro de uma instrução switch:
Você também pode criar uma entrada de enumeração por nome ou valor:
Ou você pode simplesmente obter o nome (ou seja, o nome da função) de uma entrada de enum existente:
fonte
const Monday = DaysOfWeek('Monday');
Eu encontrei esta biblioteca no github e acho que ela fornece uma alternativa muito decente para as respostas aqui.
Implementação do PHP Enum inspirada no SplEnum
function setAction(Action $action) {
format
,parse
...)final
para evitá-la)Declaração
Uso
valores de enumeração de dica de tipo:
fonte
enum
seja adicionada no PHP 7.x) porque permite dicas de tipo.__toString()
mágica, permite que você faça o que geralmente deseja com enumerações - use-as em uma declaraçãoswitch
ouif
, comparando diretamente com os valores dos consts. A melhor abordagem, com exceção do suporte a enum nativo, a IMO.Se você precisar usar enumerações globalmente únicas (ou seja, mesmo ao comparar elementos entre enumerações diferentes) e que sejam fáceis de usar, fique à vontade para usar o código a seguir. Também adicionei alguns métodos que considero úteis. Você encontrará exemplos nos comentários na parte superior do código.
fonte
eval()
apenas para poder declarar o novo tempo de execução do Enums? Eek. Eu não estou sentindo isso. Como você evita que outras classes criem uma classe Enum incorreta antes de definir a correta? Os Enums não são conhecidos antes do tempo de execução? E como o @corsiKa sugeriu, nenhum preenchimento automático do IDE. O único benefício que vejo é a codificação preguiçosa.Também gosto de enums do java e, por esse motivo, escrevo meus enums dessa maneira, acho que esse é o comportamento mais parecido com o enums do Java, é claro, se alguns que desejam usar mais métodos do java devem escrevê-lo aqui, ou em classe abstrata, mas a ideia central está incorporada no código abaixo
fonte
FruitsEnum::Apple()
maisFruitsEnum::$Apple
, mas a razão mais importante é impedir que outras pessoas definam$APPLE
, quebrando assim a enumeração de todo o aplicativo. O outro é um sinalizador estático privado simples$initialized
que garante que a chamadainit()
se torne inoperante depois de chamá-la pela primeira vez (para que ninguém possa mexer com isso)..init()
é estranho, e eu não me importo com a abordagem getter.fonte
Pode ser tão simples quanto
no futuro.
PHP RFC: Tipos enumerados
fonte
A solução mais comum que eu já vi enum no PHP foi criar uma classe enum genérica e depois estendê-la. Você pode dar uma olhada nisso .
UPDATE: Como alternativa, achei isso em phpclasses.org.
fonte
Aqui está uma biblioteca do github para lidar com enumerações de tipo seguro no php:
Essa biblioteca lida com geração de classes, armazenamento em cache de classes e implementa o padrão de design de Enumeração Segura de Tipo, com vários métodos auxiliares para lidar com enumerações, como recuperar um ordinal para classificação de enumerações ou recuperar um valor binário para combinações de enumerações.
O código gerado usa um arquivo de modelo php antigo simples, que também é configurável, para que você possa fornecer seu próprio modelo.
É teste completo coberto com phpunit.
php-enums no github (sinta-se à vontade para fazer um fork)
Uso: (@ veja use.php ou testes de unidade para obter mais detalhes)
Resultado:
fonte
Comecei a usar a abordagem abaixo, pois ela me dá a capacidade de ter segurança de tipo para parâmetros de função, preenchimento automático no NetBeans e bom desempenho. A única coisa que eu não gosto muito é que você precisa ligar
[extended class name]::enumerate();
depois de definir a classe.fonte
DaysOfWeek::$MONDAY = 3;
[extended class name]::enumerate();
após a definição, por que não faz isso na construção?Minha definição de classe Enum abaixo é fortemente tipada e muito natural de usar e definir.
Definição:
Alternar Enum
Passar Enum como parâmetro (fortemente digitado)
Eco Enum como string
Obter Enum por número inteiro
Obter Enum por nome
A classe Enum:
Adição
É claro que você também pode adicionar comentários para IDEs
fonte
Sei que esse é um tópico muito, muito, muito antigo, mas eu pensei sobre isso e queria saber o que as pessoas pensavam.
Notas: Eu estava brincando com isso e percebi que, se eu apenas modificasse a
__call()
função, você pode se aproximar ainda mais da realidadeenums
. A__call()
função lida com todas as chamadas de função desconhecidas. Então, digamos que você queira criar trêsenums
RED_LIGHT, YELLOW_LIGHT e GREEN_LIGHT. Você pode fazer isso agora fazendo o seguinte:Uma vez definido, tudo o que você precisa fazer é chamá-los novamente para obter os valores:
e você deve obter 0, 1 e 2. Divirta-se! Agora também está disponível no GitHub.
Update: Eu fiz isso para que tanto o
__get()
e__set()
funções agora sejam usadas. Isso permite que você não precise chamar uma função, a menos que queira. Em vez disso, agora você pode apenas dizer:Para a criação e obtenção dos valores. Como as variáveis não foram definidas inicialmente, o
__get()
função é chamada (porque não há um valor especificado) que vê que a entrada na matriz não foi feita. Portanto, ele faz a entrada, atribui o último valor fornecido mais um (+1), incrementa a última variável de valor e retorna VERDADEIRO. Se você definir o valor:Em seguida, a
__set()
função é chamada e o último valor é definido como o novo valor mais um (+1). Portanto, agora temos uma maneira bastante boa de fazer enums e elas podem ser criadas em tempo real.fonte
Sei que esse é um encadeamento antigo, mas nenhuma das soluções alternativas que eu vi realmente se parece com enumerações, pois quase todas as soluções exigem que você atribua valores manualmente aos itens de enumeração ou que você passe uma matriz de chaves de enumeração para uma função. Então, eu criei minha própria solução para isso.
Para criar uma classe enum usando minha solução, basta estender essa classe Enum abaixo, criar um monte de variáveis estáticas (não é necessário inicializá-las) e fazer uma chamada para yourEnumClass :: init () logo abaixo da definição da sua classe enum .
edit: Isso funciona apenas em php> = 5.3, mas provavelmente pode ser modificado para funcionar também em versões mais antigas
fonte
Agora você pode usar a classe SplEnum para construí-la nativamente. Conforme a documentação oficial.
Observe que é uma extensão que deve ser instalada, mas não está disponível por padrão. Que vem em Tipos Especiais descritos no próprio site php. O exemplo acima é retirado do site PHP.
fonte
Finalmente, uma resposta do PHP 7.1+ com constantes que não podem ser substituídas.
Se você estiver usando espaços para nome, a conclusão do código deve funcionar.
No entanto, ao fazer isso, você perde a capacidade de ocultar as constantes na família de classes (
protected
) ou somente na classe (private
). Por definição, tudo em umInterface
épublic
.Manual do PHP: Interfaces
fonte
Esta é a minha opinião sobre enum "dinâmico" ... para que eu possa chamá-lo com variáveis, ex. de um formulário.
veja a versão atualizada abaixo deste código de bloqueio ...
ATUALIZAÇÃO: Melhor maneira de fazer isso ...
Ligue com
fonte
EnumCategory::$sport = 9;
. Bem-vindo ao museu do esporte.const
é a melhor maneira de fazê-lo.A resposta aceita é o caminho a seguir e é realmente o que estou fazendo por simplicidade. A maioria das vantagens da enumeração é oferecida (legível, rápida etc.). Um conceito está faltando, no entanto: digite safety. Na maioria dos idiomas, as enumerações também são usadas para restringir os valores permitidos. Abaixo está um exemplo de como a segurança de tipo também pode ser obtida usando construtores particulares, métodos de instanciação estática e verificação de tipo:
Poderíamos ir ainda mais longe: o uso de constantes na classe DaysOfWeek pode levar ao mau uso: por exemplo, pode-se usá-lo por engano desta maneira:
que está errado (chama constante inteiro). Podemos evitar isso usando variáveis estáticas privadas em vez de constantes:
Obviamente, não é possível acessar constantes inteiras (esse era realmente o objetivo). O método intVal permite converter um objeto DaysOfWeek em sua representação inteira.
Observe que poderíamos ir além implementando um mecanismo de cache nos métodos de instanciação para economizar memória, caso as enumerações sejam amplamente utilizadas ...
Espero que isso ajude
fonte
Algumas boas soluções aqui!
Aqui está a minha versão.
Eu acho que a principal desvantagem é que os membros enum precisam ser declarados e instanciados separadamente, devido às descrições e à incapacidade do PHP de construir objetos no momento da declaração de membro estático. Acho que uma maneira de contornar isso pode ser usar a reflexão com comentários de documentos analisados.
O enum abstrato é assim:
Aqui está um exemplo de enum concreto:
Que pode ser usado assim:
E produz esta saída:
fonte
Não use reflexão. Torna extremamente difícil raciocinar sobre seu código e rastrear onde algo está sendo usado e tende a quebrar as ferramentas de análise estática (por exemplo, o que está embutido no seu IDE).
fonte
Um dos aspectos ausentes de algumas das outras respostas aqui é uma maneira de usar enumerações com dicas de tipo.
Se você definir sua enumeração como um conjunto de constantes em uma classe abstrata, por exemplo,
então você não pode digitar insinuar-lo em um parâmetro de função - por um lado, porque não é instanciável, mas também porque o tipo de
ShirtSize::SMALL
éint
, nãoShirtSize
.É por isso que enums nativas em PHP seriam muito melhores do que qualquer coisa que possamos criar. No entanto, podemos aproximar um enum mantendo uma propriedade privada que represente o valor do enum e, em seguida, restringindo a inicialização dessa propriedade a nossas constantes predefinidas. Para impedir que a enum seja instanciada arbitrariamente (sem a sobrecarga de verificar uma lista de permissões), tornamos o construtor privado.
Então nós podemos usar
ShirtSize
assim:Dessa forma, a maior diferença da perspectiva do usuário é que você precisa usar um
()
no nome da constante.Uma desvantagem é que
===
(que compara a igualdade de objetos) retornará false quando==
retornar true. Por esse motivo, é melhor fornecer umequals
método, para que os usuários não precisem se lembrar de usar==
e não===
comparar dois valores de enumeração.EDIT: Algumas das respostas existentes são muito semelhantes, especialmente: https://stackoverflow.com/a/25526473/2407870 .
fonte
Pisando na resposta de @Brian Cline, pensei em dar meus 5 centavos
fonte
include('enums.php');
]. Por alguma razão, não vê funções declaradas em Enum para classes filhas ...$currentSeason.set("Spring");
Minha tentativa de criar uma enumeração com PHP ... é extremamente limitada, pois não suporta objetos como os valores de enumeração, mas ainda é um pouco útil ...
fonte
Ontem escrevi essa aula no meu blog . Eu acho que talvez seja fácil de usar em scripts php:
Uso:
fonte