如何在PHP中实现类似Enum的功能?

时间:2009-10-06 21:48:46

标签: php

如何在PHP中使用类似Enum的功能(如Java和其他高级语言中所提供的)?我知道PHP目前不允许你创建枚举,但最接近的是什么?

9 个答案:

答案 0 :(得分:12)

或许使用const

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

答案 1 :(得分:12)

我使用类常量和一些反射技巧。

<?php
/**
 * @package Red.Core
 * @author kris@theredhead.nl
 *
 * 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;
    }
}
?>

答案 2 :(得分:8)

这是@Kris代码的更新版本,可以更好地使用较新版本的PHP。它是基于@lassombra评论而制作的。

private void doSomething() {

    Socket socket = null;

    for (int i = 0; i < 3; i++) {

        try {

            socket = connectToServer();
            break;

        } catch (IOException e) {

            // Log exception,
            // show message to user,
            // etc.
        }
    }

    if (socket != null) {
        // Ok
    } else {
        // Could not connect to server.
    }
}

private Socket connectToServer() throws IOException {

    // Always returns a valid socket.
    // Throws exception in case of problems.
}

答案 3 :(得分: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());

答案 4 :(得分:2)

提供了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包。

答案 5 :(得分:1)

您可以使用常量

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

但它不会提供一种很好的迭代方法,所以我可能会选择一个关联数组,因为它更容易管理:

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

}

答案 6 :(得分:0)

作为阵列。

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

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

答案 7 :(得分:0)

一个便宜的技巧是创建一个具有可能值的数组。但是,与上述答案不同,我选择一个键/值对相等的数组,即:

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

这样,如果($enum[$value] != $value),您知道给定的值不在集合中。

当然,如果你想要键/值对不同,那么常规阵列就是你的选择。

答案 8 :(得分:0)

就我而言,我需要存储在整个应用程序中使用的权限名称。我最后得到了一个基本的枚举抽象类,该类为枚举定义了几个实用程序函数,然后对其进行了扩展。这是基本的枚举类:

EventSource = ’Customer’ 
and EventName = ‘Login’ 
and EventType = ’ForgotEmail’
and StatusDetail = ‘Screen:AboutYou _NextButton;Zip:<>’
___ AND __
EventSource = ’Customer’
EventName = ’Login’ 
and EventType = ’ForgotEmail’ 
and StatusDetail = ’Status: Status:RetrieveEmailSuccessful 

以下是通过扩展抽象类创建的示例枚举:

SELECT 
    ab.TransactionDate, 
    SUM(CASE WHEN EventSource = 'Customer' AND EventName = 'Login' AND EventType = 'Standard' AND StatusDesc = 'Success'  
                THEN 1 ELSE 0 END) AS TotalLogin#,
    SUM(CASE WHEN EventSource = 'Customer' AND EventName = 'Login' AND EventType = 'ForgotEmail'  
                THEN 1 ELSE 0 END) AS Abandon#
FROM 
    (SELECT 
         p.TransactionDate, p.PolicyNumber, p.UserId,
         p.CustomerBrand, p.EventSource, p.EventName, p.EventType,
         p.Status, p.StatusDetail, p.StatusDesc,
         ROW_NUMBER() OVER (PARTITION BY p.PolicyNumber ORDER BY p.TransactionDate) AS row_count_policy,
         ROW_NUMBER() OVER (PARTITION BY p.UserId ORDER BY p.TransactionDate) AS row_count_user_id 
     FROM 
         [iso_report].[dbo].[PACE_Service_Log_support] p WITH (nolock)
     WHERE  
         ISNULL(EventSource, '') IN ('Customer')
         AND ISNULL(EventName, '') IN ('Login')
         AND CAST(Transactiondate AS DATE) BETWEEN '2017-01-01' AND '2017-1-1') ab 
GROUP BY 
    ab.TransactionDate
<?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);
    }
}

这是Permissions枚举的示例用法:

<?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';

}

希望这会有所帮助。