I know that PHP doesn't have native Enumerations. But I have become accustomed to them from the Java world. I would love to use enums as a way to give predefined values which IDEs' auto completion features could understand.
Constants do the trick, but there's the namespace collision problem and (or actually because) they're global. Arrays don't have the namespace problem, but they're too vague, they can be overwritten at runtime and IDEs rarely (never?) know how to autofill their keys.
Are there any solutions/workarounds you commonly use? Does anyone recall whether the PHP guys have had any thoughts or decisions around enums?
I know this is an old thread, however none of the workarounds I've seen really looked like enums, since almost all workarounds requires you to manually assign values to the enum items, or it requires you to pass an array of enum keys to a function. So I created my own solution for this.
To create an enum class using my solution one can simply extend this Enum class below, create a bunch of static variables (no need to initialize them), and make a call to yourEnumClass::init() just below the definition of your enum class.
edit: This only works in php >= 5.3, but it can probably be modified to work in older versions as well
One of the aspects missing from some of the other answers here is a way to use enums with type hinting.
If you define your enum as a set of constants in an abstract class, e.g.
then you can't type hint it in a function parameter - for one, because it's not instantiable, but also because the type of
ShirtSize::SMALL
isint
, notShirtSize
.That's why native enums in PHP would be so much better than anything we can come up with. However, we can approximate an enum by keeping a private property which represents the value of the enum, and then restricting the initialization of this property to our predefined constants. To prevent the enum from being instantiated arbitrarily (without the overhead of type-checking a whitelist), we make the constructor private.
Then we can use
ShirtSize
like this:This way, the biggest difference from the user's perspective is that you have to tack on a
()
on the constant's name.One downside though is that
===
(which compares object equality) will return false when==
returns true. For that reason, it's best to provide anequals
method, so that users don't have to remember to use==
and not===
to compare two enum values.EDIT: A couple of the existing answers are very similar, particularly: https://stackoverflow.com/a/25526473/2407870.
It might be as simple as
in the future.
PHP RFC: Enumerated Types
Don't use reflection. It makes it extremely difficult to reason about your code and track down where something is being used, and tends to break static analysis tools (eg what's built into your IDE).
Here is a github library for handling type-safe enumerations in php:
This library handle classes generation, classes caching and it implements the Type Safe Enumeration design pattern, with several helper methods for dealing with enums, like retrieving an ordinal for enums sorting, or retrieving a binary value, for enums combinations.
The generated code use a plain old php template file, which is also configurable, so you can provide your own template.
It is full test covered with phpunit.
php-enums on github (feel free to fork)
Usage: (@see usage.php, or unit tests for more details)
Output:
The accepted answer is the way to go and is actually what I am doing for simplicity. Most advantages of enumeration are offered (readable, fast, etc.). One concept is missing, however: type safety. In most languages, enumerations are also used to restrict allowed values. Below is an example of how type safety can also be obtained by using private constructors, static instantiation methods and type checking:
We could even go further: using constants in the DaysOfWeek class might lead to misusage: e.g. one might mistakenly use it this way:
which is wrong (calls integer constant). We can prevent this using private static variables instead of constants:
Of course, it is not possible to access integer constants (this was actually the purpose). The intVal method allows to convert a DaysOfWeek object to its integer representation.
Note that we could even go further by implementing a caching mechanism in instantiation methods to save memory in the case enumerations are extensively used...
Hope this will help