📜 ⬆️ ⬇️

Enumeration implementation (Enum) in PHP with type checking

Sometimes you have to use strongly typed parameters in the code, but the PHP language itself is not strictly typed (for example, C #, in which there is such a data type as enums - Enum). However, a way out of this situation can still be found. Rummaging through the expanses of the Internet, I did not find a suitable solution for me. I offer you my solution to this problem.

The problem was as follows. It is necessary to implement a function that would accept a strongly typed object (class) as input, however, in the body of functions, it is necessary to enumerate the values ​​of this class and compare it with predefined constants (of the same class):

function test(Data $data) { switch ((string)$data) { case Data::ID: echo 'This is ID' . PHP_EOL; break; case Data::STRING: echo 'This is a STRING' . PHP_EOL; break; } } 


However, it immediately becomes apparent that PHP will warn you that it is not possible to use an object as a parameter of a switch .
')
The solution to the problem is to implement an abstract class, as the base class for all classes, where predefined constants will be used, with which the comparison will take place in the switch .

Code for this class:

 /** * Base class, witch implements enumeration in child classes. * * PHP version 5 * * @author Andrey Klimenko * @license 2012, Andrey Klimenko * @version 1.0.0 */ abstract class AbstractEnum { /** * @var AbstractEnum Class instance */ protected static $instance = null; /** * @var mixed Value to compare with class constants */ protected static $value; /** * Protected constructor (realize singleton pattern). * * @final */ protected final function __construct() { } /** * Protect from object cloning (realize singleton pattern). * * @final */ protected final function __clone() { } /** * Protect from reconstruct resources that the object may have (realize singleton pattern). * * @final */ protected final function __wakeup() { } /** * Return instance of this object. * * @static * * @param mixed $value Constant value * * @return AbstractEnum */ public static function getInstance($value) { if (self::$instance === null) { self::$instance = new static(); } self::setConstant($value); // Set value of constant return self::$instance; } /** * Prepare to return constant value, given in getInstance() function. * * @return string */ public final function __toString() { return (string)static::$value; } /** * Set constant value. * * @static * * @param mixed $value Constant value * */ protected static function setConstant($value) { $class = new \ReflectionClass(static::$instance); // Get this class reflection $constants = array_flip($class->getConstants()); // Get constants of this object // Check if constant with given value exist if (array_key_exists($value, $constants)) { $constantName = $constants[$value]; static::$value = $class->getConstant($constantName); // Set constant value } else { trigger_error('Class does not have constant with this value: `' . $value . '`', E_USER_ERROR); } } } 


Now we are implementing a class that inherits from the abstract class described above. This class is a class that includes constants with which we will make a comparison.

 /** * Sample class, witch implement AbstractEnum abstract class. * * PHP version 5 * * @author Andrey Klimenko * @license 2012, Andrey Klimenko * @version 1.0.0 */ class Data extends AbstractEnum { const ID = 1; // First constant const STRING = 2; // Second constant } 


Now we will implement the function in which we check the work of our class. The main problem, as I said, was the strict typification of the parameter passed to it. We specify our class Data as the type.

 /** * Test function. * * @param Data $data Class to check value with. * * @return void */ function test(Data $data) { // First - convert object to string switch ((string)$data) { // compare needed values case Data::ID: echo 'This is ID' . PHP_EOL; break; case Data::STRING: echo 'This is a STRING' . PHP_EOL; break; } } 


And finally - check our function:

 for ($i = 1; $i < 3; $i++) { test(Data::getInstance($i)); } 


Everything works as we wanted. That's all. I hope someone this design is useful.

Source: https://habr.com/ru/post/173311/


All Articles