Author: Rafa Rodriguez
Updated on: 2019-09-24
Posted on: 2019-09-24
Package: Div PHP Enum Class
Until today PHP does not have a native enum type. It offers a very basic implementation using SPL extension, but I prefer to believe that implementation is not ideal.
Alternatively, the Div PHP Enum package provides is a solution for this using classes. Thanks to some interesting features of PHP, you can make a taxonomy (hierarchy of terms) and give behavior to each term similar to what we can achieve using the Java language.
Read read article to learn how you can implement PHP enums using pure PHP code, thus without additional extensions.
Introduction to Enums in PHP
An enumeration type, "enum" for short, is a data type that is used to define unique values that are associated to names. Enums can be used instead of hard coded strings to represent, for example, the status of a blog post in a structured and typed way.
Until today PHP does not have a native enum type. It offers a very basic implementation using SPL extension, but I prefer to believe that implementation is not ideal.
There is a popular package written by Matthieu Napoli called myclabs/php-enum. It is a package that many of us have been using in countless projects. It is really awesome.
Alternatively, the Div PHP Enum package provides is a solution for this using classes. Thanks to some interesting features of PHP, you can make a taxonomy (hierarchy of terms) and give behavior to each term similar to what we can achieve using the Java language.
In July 2019, I wrote a gist while I was searching a solution for this. Later I have converted the gist into a real project.
The problem
Some solutions use PHP constants, but I prefer to believe they are not ideal because they have limitations. For instance how can you validate that HOT or COLD are acceptable as function parameter values?
<?php const HOT = 1;
function doSomething(int $temperature) { /* ... */}
const COLD = 2; const FIRE = 1; const ICE = 2; doSomething(FIRE);
The Solution
Use PHP!
The class divengine\enum can help solving the problem using just pure PHP. but keep in mind: the most important solution is the concept of this library.
It uses class names as a way to define enumerated values.
We need have built-in support for enums in PHP, but, for now, this is a solution that works.
With this class, you can solve the following problems:
1. Constants with different names and equal value can be used in the declaration of function arguments allowing PHP to do type checking using type hinting support.
2. It also makes it possible for PHP IDEs and other types of tools to perform loose static analysis benefits like auto completion and refactoring
3. It can also be used in PHPDOC like documentation comments to provide type hints to also help solving the problem 1.
Examples
<?php namespace MyEnums; use divengine\enum; class Temperature extends enum {/Father of all types of temperatures/} class ExtremeTemperature extends Temperature {/Father of all types of extreme temperatures/} class FIRE extends ExtremeTemperature {} class ICE extends ExtremeTemperature {} class NormalTemperature extends Temperature {/Father of all types of normal temperatures/} class HOT extends NormalTemperature {} class COOL extends NormalTemperature {} class COLD extends NormalTemperature {}
Second use your enums:
<?php use MyEnums; // Constants are good tricks, but optional const COOL = COOL::class; class AllTemperatures { const COOL = COOL::class; // maybe better const HOT = 'Enums\\HOT'; // ugly !!! //... } // Define some function with type hinting function WhatShouldIdo(Temperature $temperature) { switch (true) { case $temperature instanceof ExtremeTemperature: switch (true) { case $temperature instanceof FIRE: return "Call the fire department"; case $temperature instanceof ICE: return "Warm up"; } break; case $temperature instanceof NormalTemperature: switch ($temperature) { case HOT::class: // compare using classname return "Drink a bear :D"; case COOL or AllTemperatures::COOL: // compare using constants return "Just go away !"; case 'Enums\\COLD': // compare using string, ugly !!! return "Wear a coat"; } break; } return "I don't know"; } // Call to function with a instance of any Temperature echo WhatShouldIdo(new HOT()) . PHP_EOL;
Do you like Java programming language? Here is similar code using Java
You actually can use switch statements on enums, but you can not switch do the same using Strings before Java 7.
You may consider using polymorphic method dispatch with Java enums rather than an explicit switch. Note that enums are objects in Java, not just symbols for ints like they are in C/C++.
You can have a method using an enum type. Then instead of writing a switch, just call the method - one line of code: done!
One of the nice things about this approach is that it is simply impossible to get certain types of errors. You can't miss a switch case (you can incorrectly implement a method for a particular constant, but there's nothing that will ever totally prevent that from happening!). There's no switch "default" to worry about. Also, I've seen code that puts enum constants into arrays and then indexes into the arrays - this opens the possibility of array index out of bounds exceptions - just use the enum! Java enums are very, very powerful. Learn all that you can about them to use them effectively.
public enum Temperature { HOT { @Override public void whatShouldIdo() { System.out.println("Drink a bear!"); } }, COLD { @Override public void whatShouldIdo() { System.out.println("Wear a coat!"); } }; public abstract void whatShouldIdo();
// ...
void aMethodSomewhere(final Temperature temperature) {
// here is where the switch would be,
// now it's one line of code!
} doSomeStuff();
temperature.whatShouldIdo(); doSomeOtherStuff(); }
Also note if you have several enum constants that all have the same behavior for a particular method, you can simply gather that shared code in an enum method that is not overridden by every constant (final protected) and then call that method from the appropriate methods.
So, add "final protected void commonMethod() { ... }" and then the implementation of method() in each constant would just call commonMethod().
And.... what about PHP ?
Here follows a similar solution:
<?php abstract class Temperature extends divengine\enum { public function whatShouldIdo() {} } class HOT extends Temperature { public function whatShouldIdo() { echo "Drink a bear!"; } } class COLD extends Temperature { public function whatShouldIdo() { echo "Wear a coat!"; } } // ....
function someStuff(Temperature $t) { $t->whatShouldIdo(); } someStuff( new HOT() );
Conclusion
This is my contribution to implement a flexible solution to implement enums in PHP. The project will continue to have improvements in terms of features and documentation. I hope this solution serves many of you that like me had the need for a better approach to implement enumerated values in PHP.
If you liked this article share it with other PHP developer colleagues that like you appreciated learning more about PHP techniques to implement better PHP projects.
If you have questions or doubts, feel free to comment about this project below.
You need to be a registered user or login to post a comment
1,537,265 PHP developers registered to the PHP Classes site.
Be One of Us!
Login Immediately with your account on:
Comments:
No comments were submitted yet.