Подтвердить что ты не робот

Как реализовать Enum как функциональность в PHP?

Как можно использовать функции, подобные Enum (как указано на Java и других языках высокого уровня) в PHP? Я знаю, что PHP не позволяет вам создавать перечисления в настоящее время, но что может быть самым близким?

4b9b3361

Ответ 1

Использование const, возможно.

class SomeClass {
    const FIRSTVAL = 1;
    const SECONDVAL = 2;
};

Ответ 2

Я использую константы класса и немного обтекания отражения.

<?php
/**
 * @package Red.Core
 * @author [email protected]
 *
 * Implements the abstract base for all enum types
 *
 * example of a typical enum:
 *
 *    class DayOfWeek extends Enum
 *    {
 *        const Sunday    = 0;
 *        const Monday    = 1;
 *        const Tuesday   = 2;
 *        const Wednesday = 3;
 *        const Thursday  = 4;
 *        const Friday    = 5;
 *        const Saturday  = 6;
 *    }
 *
 * usage examples:
 *
 *     $monday = Enum::FromString( 'DayOfWeek::Monday' );           // (int) 1
 *     $monday = DayOfWeek::Monday                                  // (int) 1
 *     $monday = Enum::ToString( 'DayOfWeek', DayOfWeek::Monday );  // (string) "DayOfWeek::Monday"
 *     $monday = Enum::Label( 'DayOfWeek', DayOfWeek::Monday );     // (string) "Monday"
 *
 **/
abstract class Enum
{
    // make sure there are never any instances created
    final private function __construct()
    {
        throw new Exception( 'Enum and Subclasses cannot be instantiated.' );
    }

    /**
     * Give the integer associated with the const of the given string in the format of "class:const"
     *
     * @param string $string
     * @return integer
     */
    final public static function FromString( $string )
    {
        if ( strpos( $string, '::' ) < 1 )
        {
            throw new Exception( 'Enum::FromString( $string ) Input string is not in the expected format.' );
        }
        list( $class, $const ) = explode( '::', $string );

        if ( class_exists( $class, false ) )
        {
            $reflector = new ReflectionClass( $class );
            if ( $reflector->IsSubClassOf( 'Enum' ) )
            {
                if ( $reflector->hasConstant( $const ) )
                {
                    return eval( sprintf( 'return %s;', $string ) );
                }
            }
        }
        throw new Excption( sprintf( '%s does not map to an Enum field', $string ) );
    }

    final public static function IsValidValue( $enumType, $enumValue )
    {
        if ( class_exists( $enumType ) )
        {
            $reflector = new ReflectionClass( $enumType );
            if ( $reflector->IsSubClassOf( 'Enum' ) )
            {
                foreach( $reflector->getConstants() as $label => $value )
                {
                    if ( $value == $enumValue )
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    final public static function IsValidLabel( $enumType, $enumValue )
    {
        if ( class_exists( $enumType ) )
        {
            $reflector = new ReflectionClass( $enumType );
            if ( $reflector->IsSubClassOf( 'Enum' ) )
            {
                foreach( $reflector->getConstants() as $label => $value )
                {
                    if ( $label == $enumValue )
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * For a given $enumType, give the complete string representation for the given $enumValue (class::const)
     *
     * @param string $enumType
     * @param integer $enumValue
     * @return string
     */
    final public static function ToString( $enumType, $enumValue )
    {
        $result = 'NotAnEnum::IllegalValue';

        if ( class_exists( $enumType, false ) )
        {
            $reflector = new ReflectionClass( $enumType );
            $result = $reflector->getName() . '::IllegalValue';
            foreach( $reflector->getConstants() as $key => $val )
            {
                if ( $val == $enumValue )
                {
                    $result = str_replace( 'IllegalValue', $key, $result );
                    break;
                }
            }
        }
        return $result;
    }

    /**
     * For a given $enumType, give the label associated with the given $enumValue (const name in class definition)
     *
     * @param string $enumType
     * @param integer $enumValue
     * @return string
     */
    final public static function Label( $enumType, $enumValue )
    {
        $result = 'IllegalValue';

        if ( class_exists( $enumType, false ) )
        {
            $reflector = new ReflectionClass( $enumType );

            foreach( $reflector->getConstants() as $key => $val )
            {
                if ( $val == $enumValue )
                {
                    $result = $key;
                    break;
                }
            }
        }
        return $result;
    }
}
?>

Ответ 3

Это обновленная версия из кода @Kris, чтобы лучше работать с более новыми версиями PHP. Он был составлен на основе комментария @lassombra.

/**
 * Implements the abstract base for all enum types
 * @see http://stackoverflow.com/a/2324746/1003020
 * @see http://stackoverflow.com/a/254543/1003020
 *
 * Example of a typical enum:
 *
 *    class DayOfWeek extends Enum
 *    {
 *        const Sunday    = 0;
 *        const Monday    = 1;
 *        const Tuesday   = 2;
 *        const Wednesday = 3;
 *        const Thursday  = 4;
 *        const Friday    = 5;
 *        const Saturday  = 6;
 *    }
 *
 * Usage examples:
 *
 *     $monday = DayOfWeek::Monday                      // (int) 1
 *     DayOfWeek::isValidName('Monday')                 // (bool) true
 *     DayOfWeek::isValidName('monday', $strict = true) // (bool) false
 *     DayOfWeek::isValidValue(0)                       // (bool) true
 *     DayOfWeek::fromString('Monday')                  // (int) 1
 *     DayOfWeek::toString(DayOfWeek::Tuesday)          // (string) "Tuesday"
 *     DayOfWeek::toString(5)                           // (string) "Friday"
 **/
abstract class Enum
{
    private static $constCacheArray = NULL;

    private static function getConstants()
    {
        if (self::$constCacheArray == NULL) {
            self::$constCacheArray = [];
        }
        $calledClass = get_called_class();
        if (!array_key_exists($calledClass, self::$constCacheArray)) {
            $reflect = new \ReflectionClass($calledClass);
            self::$constCacheArray[$calledClass] = $reflect->getConstants();
        }
        return self::$constCacheArray[$calledClass];
    }

    public static function isValidName($name, $strict = false)
    {
        $constants = self::getConstants();

        if ($strict) {
            return array_key_exists($name, $constants);
        }

        $keys = array_map('strtolower', array_keys($constants));
        return in_array(strtolower($name), $keys);
    }

    public static function isValidValue($value, $strict = true)
    {
        $values = array_values(self::getConstants());
        return in_array($value, $values, $strict);
    }

    public static function fromString($name)
    {
        if (self::isValidName($name, $strict = true)) {
            $constants = self::getConstants();
            return $constants[$name];
        }

        return false;
    }

    public static function toString($value)
    {
        if (self::isValidValue($value, $strict = true)) {
            return array_search($value, self::getConstants());
        }

        return false;
    }
}

Ответ 4

Вы также можете использовать этот:

class Enum{

    private $m_valueName = NULL;

    private function __construct($valueName){
        $this->m_valueName = $valueName;
    }

    public static function __callStatic($methodName, $arguments){
        $className = get_called_class();
        return new $className($methodName);
    }

    function __toString(){
        return $this->m_valueName;
    }
}

class NotificationType extends Enum{
    const Notification = NULL;
    const Warning = NULL;
    const Error = NULL;
}

function Test(NotificationType $type){
    echo "Test function, type: $type<br>";
}

Test(NotificationType::Warning());

Ответ 5

Существует класс SplEnum.

Пример использования из документов:

<?php
class Month extends SplEnum {
    const __default = self::January;

    const January = 1;
    const February = 2;
    const March = 3;
    const April = 4;
    const May = 5;
    const June = 6;
    const July = 7;
    const August = 8;
    const September = 9;
    const October = 10;
    const November = 11;
    const December = 12;
}

echo new Month(Month::June) . PHP_EOL;

try {
    new Month(13);
} catch (UnexpectedValueException $uve) {
    echo $uve->getMessage() . PHP_EOL;
}

В приведенном выше примере выведите

6
Value not a const in enum Month

Другая возможность заключается в использовании пакета myclabs/php-enum.

Ответ 6

Вы можете использовать константы

class myClass {
    const aValue = 123;
    const aString = "ABC";
};

Но это не дало бы приятного способа итерации через них, поэтому я бы выбрал подходящий массив, поскольку было бы легче управлять:

class myClass{
  $enum = array ("first" => 123, 
                "second" => "ABC");

}

Ответ 7

Как массив.

$arr = array('A','B','C','D');

$find = 'A';
$key = array_search($find,$arr);
echo $arr[$key];

Ответ 8

Дешевый трюк заключается в создании массива с возможными значениями. Однако, в отличие от приведенных выше ответов, я бы выбрал массив, в котором пары ключ/значение равны, то есть:

<?php
$enum = Array(
'apple' => 'apple',
'pear' => 'pear',
'orange' => 'orange'
);
?>

Таким образом, если ($enum[$value] != $value), вы знаете, что указанное значение не находится в наборе.

Конечно, если вы хотите, чтобы пары ключ/значение были разными, регулярный массив мог бы пойти.

Ответ 9

В моем случае мне нужно было хранить имена разрешений, которые используются в приложении. Я закончил базовым абстрактным классом перечисления, который определил несколько вспомогательных функций для перечислений, а затем расширил его. Вот базовый перечислимый класс:

<?php

namespace App\Enums;


use ReflectionClass;

abstract class BasicEnum {
    private static $constCacheArray = NULL;

    public static function getConstants() {
        if (self::$constCacheArray == NULL) {
            self::$constCacheArray = [];
        }
        $calledClass = get_called_class();
        if (!array_key_exists($calledClass, self::$constCacheArray)) {
            $reflect = new ReflectionClass($calledClass);
            self::$constCacheArray[$calledClass] = $reflect->getConstants();
        }
        return self::$constCacheArray[$calledClass];
    }

    public static function isValidName($name, $strict = false) {
        $constants = self::getConstants();

        if ($strict) {
            return array_key_exists($name, $constants);
        }

        $keys = array_map('strtolower', array_keys($constants));
        return in_array(strtolower($name), $keys);
    }

    public static function isValidValue($value, $strict = true) {
        $values = array_values(self::getConstants());
        return in_array($value, $values, $strict);
    }
}

Вот примеры перечислений, созданных путем расширения абстрактного класса:

<?php

namespace App\Enums;


class Permissions extends BasicEnum
{
    const COMMENTS_CREATE = 'create comments';
    const COMMENTS_VIEW = 'view comments';
    const COMMENTS_EDIT = 'edit comments';
    const COMMENTS_DELETE = 'delete comments';
    const COMMENTS_RESTORE = 'restore comments';

    const REACTIONS_CREATE = 'create reactions';
    const REACTIONS_VIEW = 'view reactions';
    const REACTIONS_EDIT = 'edit reactions';
    const REACTIONS_DELETE = 'delete reactions';
    const REACTIONS_RESTORE = 'restore reactions';

    const QUESTIONS_CREATE = 'create questions';
    const QUESTIONS_VIEW = 'view questions';
    const QUESTIONS_EDIT = 'edit questions';
    const QUESTIONS_DELETE = 'delete questions';
    const QUESTIONS_RESTORE = 'restore questions';

    const PERMISSIONS_CREATE = 'create permissions';
    const PERMISSIONS_VIEW = 'view permissions';
    const PERMISSIONS_EDIT = 'edit permissions';
    const PERMISSIONS_DELETE = 'delete permissions';
    const PERMISSIONS_RESTORE = 'restore permissions';

}

<?php

namespace App\Enums;


class PostTypes extends BasicEnum
{
    const POST    = 'post';
    const NEWS    = 'news';
    const SERVICE    = 'service';
}

И вот пример использования перечисления Permissions:

/**
 * Determine whether the user can create reactions.
 *
 * @param User $user
 * @return mixed
 */
public function create(User $user)
{
    return $user->can(Permissions::REACTIONS_CREATE);
}

Надеюсь это поможет.