PHP và liệt kê


1149

Tôi biết rằng PHP không có Bảng liệt kê riêng. Nhưng tôi đã quen với chúng từ thế giới Java. Tôi rất thích sử dụng enum như một cách để đưa ra các giá trị được xác định trước mà các tính năng tự động hoàn thành của IDE có thể hiểu được.

Các hằng số thực hiện mánh khóe, nhưng có vấn đề xung đột không gian tên và (hoặc thực tế là ) chúng là toàn cầu. Mảng không có vấn đề về không gian tên, nhưng chúng quá mơ hồ, chúng có thể bị ghi đè khi chạy và IDE hiếm khi (không bao giờ?) Biết cách tự động điền khóa của chúng.

Có giải pháp / cách giải quyết nào bạn thường sử dụng không? Có ai nhớ lại liệu các anh chàng PHP đã có bất kỳ suy nghĩ hay quyết định nào xung quanh enums không?



1
Tôi đã tạo ra một công việc xung quanh hàm liệt kê các hằng số theo bitwise hay không. Không nhận thấy bạn đã hỏi điều này trước đây, nhưng tôi có một giải pháp tốt hơn các biến lớp ở đây: stackoverflow.com/questions/3836385/ợi
NoodleOfDeath


Bạn có phiền chia sẻ thêm một chút về vấn đề Hằng không? "Các hằng số thực hiện mánh khóe, nhưng có vấn đề va chạm không gian tên và (hoặc thực sự là vì) chúng là toàn cầu."
XuDing

Câu trả lời:


1492

Tùy thuộc vào trường hợp sử dụng, tôi thường sử dụng một cái gì đó đơn giản như sau:

abstract class DaysOfWeek
{
    const Sunday = 0;
    const Monday = 1;
    // etc.
}

$today = DaysOfWeek::Sunday;

Tuy nhiên, các trường hợp sử dụng khác có thể yêu cầu xác nhận nhiều hơn các hằng số và giá trị. Dựa trên các ý kiến ​​dưới đây về sự phản ánh và một vài ghi chú khác , đây là một ví dụ mở rộng có thể phục vụ tốt hơn cho nhiều trường hợp:

abstract class BasicEnum {
    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);
    }
}

Bằng cách tạo một lớp enum đơn giản mở rộng BasicEnum, giờ đây bạn có khả năng sử dụng các phương thức để xác thực đầu vào đơn giản:

abstract class DaysOfWeek extends BasicEnum {
    const Sunday = 0;
    const Monday = 1;
    const Tuesday = 2;
    const Wednesday = 3;
    const Thursday = 4;
    const Friday = 5;
    const Saturday = 6;
}

DaysOfWeek::isValidName('Humpday');                  // false
DaysOfWeek::isValidName('Monday');                   // true
DaysOfWeek::isValidName('monday');                   // true
DaysOfWeek::isValidName('monday', $strict = true);   // false
DaysOfWeek::isValidName(0);                          // false

DaysOfWeek::isValidValue(0);                         // true
DaysOfWeek::isValidValue(5);                         // true
DaysOfWeek::isValidValue(7);                         // false
DaysOfWeek::isValidValue('Friday');                  // false

Như một lưu ý phụ, bất cứ khi nào tôi sử dụng phản xạ ít nhất một lần trên lớp tĩnh / const nơi dữ liệu sẽ không thay đổi (chẳng hạn như trong enum), tôi lưu trữ kết quả của các cuộc gọi phản xạ đó, vì sử dụng các đối tượng phản xạ mới mỗi lần cuối cùng sẽ có một tác động hiệu suất đáng chú ý (Được lưu trữ trong một mảng kết hợp cho nhiều enum).

Bây giờ hầu hết mọi người đã cuối cùng đã nâng cấp lên ít nhất 5.3, và SplEnumcó sẵn, đó chắc chắn là một lựa chọn khả thi cũng - miễn là bạn không nhớ các khái niệm truyền thống unintuitive của việc có enum thực tế instantiations suốt codebase của bạn. Trong ví dụ trên, BasicEnumDaysOfWeekkhông thể được khởi tạo ở tất cả, cũng không nên.


70
Tôi cũng dùng cái này Bạn cũng có thể xem xét việc tạo lớp abstractfinalvì vậy nó không thể được khởi tạo hoặc mở rộng.
ryeguy

21
Bạn có thể làm cho một lớp cả abstractfinal? Tôi biết trong Java điều này không được phép. Bạn có thể làm điều đó trong php?
corsiKa

20
@ryeguy Có vẻ như bạn không thể làm cho cả hai abstractfinal. Trong trường hợp đó, tôi sẽ đi trừu tượng.
Nicole

45
Về trừu tượng hoặc cuối cùng; Tôi làm cho họ cuối cùng và cung cấp cho họ một nhà xây dựng riêng trống
rael_kid

21
Hãy cẩn thận với việc sử dụng 0, vì vậy bạn không gặp phải bất kỳ vấn đề so sánh sai lệch nào, ví dụ như sự tương đương với nullvà bạn bè trong một switchtuyên bố. Đã ở đó.
yitznewton

185

Có một phần mở rộng bản địa, quá. các SplEnum

SplEnum cung cấp khả năng mô phỏng và tạo các đối tượng liệt kê tự nhiên trong PHP.

http://www.php.net/manual/en/ class.splenum.php

Chú ý:

https://www.php.net/manual/en/spl-types.installation.php

Phần mở rộng PECL không được đóng gói với PHP.

Một DLL cho phần mở rộng PECL này hiện không có sẵn.


4
Dưới đây là một ví dụ với splenum: dreamincode.net/forums/topic/201638-enum-in-php
Nordes

4
Tôi quay lại, tôi thích nó hơn khi tôi có thể nhìn thấy liên kết. Nó cho tôi thông tin bối cảnh.
markus

5
Tôi lại lăn lộn. Tôi không muốn các bạn chỉnh sửa liên kết.
markus

6
Hãy cẩn thận khi sử dụng này. Các loại SPL là thử nghiệm: "Phần mở rộng này là TRẢI NGHIỆM. Hành vi của phần mở rộng này bao gồm tên các chức năng của nó và bất kỳ tài liệu nào khác xung quanh phần mở rộng này có thể thay đổi mà không cần thông báo trong bản phát hành PHP trong tương lai. "
bzeaman

6
SplEnum không được đóng gói với PHP, nó cần mở rộng
SPL_Types

46

Còn hằng số lớp thì sao?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

    public function echoConstant()
    {
        echo self::SOME_CONSTANT;
    }
}

echo YourClass::SOME_CONSTANT;

$c = new YourClass;
$c->echoConstant();

Tôi thích cách tiếp cận đơn giản này
David Lemon

echoConstantcó thể được thay thế bằng __toString. Và sau đó đơn giảnecho $c
Justinas

35

Câu trả lời hàng đầu ở trên là tuyệt vời. Tuy nhiên, nếu bạn thực hiện extendtheo hai cách khác nhau, thì bất kỳ tiện ích mở rộng nào được thực hiện trước tiên sẽ dẫn đến một cuộc gọi đến các chức năng sẽ tạo bộ đệm. Bộ đệm này sau đó sẽ được sử dụng cho tất cả các cuộc gọi tiếp theo, bất kể cuộc gọi mở rộng nào được bắt đầu bởi ...

Để giải quyết điều này, thay thế hàm biến và hàm đầu tiên bằng:

private static $constCacheArray = null;

private static function getConstants() {
    if (self::$constCacheArray === null) self::$constCacheArray = array();

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

    return self::$constCacheArray[$calledClass];
}

2
Có vấn đề này rất. Brian hoặc ai đó có đặc quyền chỉnh sửa nên chạm vào nó trong câu trả lời được chấp nhận. Tôi đã giải quyết nó trong mã của mình bằng phương thức 'static ::' thay vì 'self ::' trong hàm getConstants () và khai báo lại $ constCache trong enum con.
Sp3igel

Nó có thể không gợi cảm, nhưng sử dụng hằng số giao diện có thể là cách tốt nhất để sử dụng PHP.
Anthony Rutledge

27

Tôi đã sử dụng các lớp với hằng số:

class Enum {
    const NAME       = 'aaaa';
    const SOME_VALUE = 'bbbb';
}

print Enum::NAME;

27

Tôi sử dụng interfacethay vì class:

interface DaysOfWeek
{
    const Sunday = 0;
    const Monday = 1;
    // etc.
}

var $today = DaysOfWeek::Sunday;

6
class Foo implements DaysOfWeek { }và sau đó Foo::Sunday... cái gì?
Dan Lugg

3
Tác giả của câu hỏi yêu cầu một giải pháp cho hai điều: không gian tên và tự động hoàn thành bởi các IDE. Như câu trả lời được xếp hạng hàng đầu được đề xuất, cách dễ nhất là sử dụng class(hoặc interface, đó chỉ là vấn đề ưu tiên).
Andi T

4
các giao diện được sử dụng để thực thi tính toàn vẹn thực hiện của lớp, điều này nằm ngoài phạm vi của một giao diện
user3886650

2
@ user3886650 Các giao diện có thể và được / được sử dụng trong Java để giữ các giá trị không đổi. Vì vậy, bạn không bị buộc phải khởi tạo một lớp chỉ để nhận các giá trị không đổi và bất kỳ IDE nào cũng cung cấp hoàn thành mã trên chúng. Ngoài ra nếu bạn tạo một lớp thực hiện giao diện đó, nó sẽ kế thừa tất cả các hằng số đó - đôi khi khá tiện dụng.
Alex

@ user3886650 Đúng, nhưng trong PHP, các giao diện có thể có các hằng số. Ngoài ra, các hằng số giao diện này không thể bị ghi đè bằng cách triển khai các lớp hoặc con của chúng. Trên thực tế, đây là câu trả lời tốt nhất về mặt PHP, bởi vì bất kỳ thứ gì có thể bị ghi đè đều không thực sự hoạt động như một hằng số. Hằng số có nghĩa là hằng số, không đôi khi (mặc dù đa hình có thể hữu ích đôi khi).
Anthony Rutledge

25

Tôi đã nhận xét về một số câu trả lời khác ở đây, vì vậy tôi đoán rằng tôi cũng sẽ cân nhắc. Vào cuối ngày, vì PHP không hỗ trợ các kiểu liệt kê, bạn có thể đi theo một trong hai cách: loại bỏ các bảng liệt kê đã nhập hoặc sống với thực tế là chúng cực kỳ khó để hack ra một cách hiệu quả.

Tôi thích sống với thực tế, và thay vào đó sử dụng constphương pháp mà các câu trả lời khác ở đây đã sử dụng theo cách này hay cách khác:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

Một ví dụ liệt kê:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

Sử dụng Enumnhư một lớp cơ sở mà tất cả các phép liệt kê khác mở rộng cho phép các phương thức của trình trợ giúp, như toArray, isValidv.v. Đối với tôi, việc liệt kê ( và quản lý trường hợp của họ ) cuối cùng lại quá lộn xộn.


Giả thuyết

Nếu , tồn tại một __getStaticphương pháp ma thuật ( và tốt nhất là một __equalsphương pháp ma thuật nữa ) thì phần lớn điều này có thể được giảm thiểu bằng một kiểu mẫu đa hình.

( Sau đây là giả thuyết; nó sẽ không hoạt động, mặc dù có lẽ một ngày nào đó nó sẽ hoạt động )

final class TestEnum
{

    private static $_values = [
        'FOO' => 1,
        'BAR' => 2,
        'QUX' => 3,
    ];
    private static $_instances = [];

    public static function __getStatic($name)
    {
        if (isset(static::$_values[$name]))
        {
            if (empty(static::$_instances[$name]))
            {
                static::$_instances[$name] = new static($name);
            }
            return static::$_instances[$name];
        }
        throw new Exception(sprintf('Invalid enumeration value, "%s"', $name));
    }

    private $_value;

    public function __construct($name)
    {
        $this->_value = static::$_values[$name];
    }

    public function __equals($object)
    {
        if ($object instanceof static)
        {
            return $object->_value === $this->_value;
        }
        return $object === $this->_value;
    }

}

$foo = TestEnum::$FOO; // object(TestEnum)#1 (1) {
                       //   ["_value":"TestEnum":private]=>
                       //   int(1)
                       // }

$zap = TestEnum::$ZAP; // Uncaught exception 'Exception' with message
                       // 'Invalid enumeration member, "ZAP"'

$qux = TestEnum::$QUX;
TestEnum::$QUX == $qux; // true
'hello world!' == $qux; // false

Tôi thực sự thích sự đơn giản của câu trả lời này. Đó là loại điều bạn có thể quay lại sau và nhanh chóng hiểu cách thức hoạt động của nó mà không làm cho nó trông giống như bạn đã thực hiện một số cách tiếp cận bị hack. Thật xấu hổ vì nó không có nhiều phiếu bầu hơn.
Phản ứng

23

Vâng, đối với một java đơn giản như enum trong php, tôi sử dụng:

class SomeTypeName {
    private static $enum = array(1 => "Read", 2 => "Write");

    public function toOrdinal($name) {
        return array_search($name, self::$enum);
    }

    public function toString($ordinal) {
        return self::$enum[$ordinal];
    }
}

Và để gọi nó:

SomeTypeName::toOrdinal("Read");
SomeTypeName::toString(1);

Nhưng tôi là người mới bắt đầu PHP, phải vật lộn với cú pháp nên đây có thể không phải là cách tốt nhất. Tôi đã thử nghiệm một số với Hằng số lớp, sử dụng Reflection để lấy tên hằng từ giá trị của nó, có thể gọn gàng hơn.


Câu trả lời tốt, hầu hết các câu trả lời khác đang sử dụng các lớp. Bạn không thể có các lớp lồng nhau mặc dù.
Keyo

Điều này có lợi ích là có thể lặp lại thông qua các giá trị với foreach. Và bất lợi là một giá trị bất hợp pháp không bị bắt.
Bob Stein

2
Không có tự động hoàn thành trong IDE, vì vậy sẽ kích thích công việc đoán. Các hằng số sẽ cho phép tự động hoàn thành, âm thanh tốt hơn.
KrekkieD

19

Bốn năm sau tôi lại bắt gặp điều này. Cách tiếp cận hiện tại của tôi là điều này vì nó cho phép hoàn thành mã trong IDE cũng như loại an toàn:

Lớp cơ sở:

abstract class TypedEnum
{
    private static $_instancedValues;

    private $_value;
    private $_name;

    private function __construct($value, $name)
    {
        $this->_value = $value;
        $this->_name = $name;
    }

    private static function _fromGetter($getter, $value)
    {
        $reflectionClass = new ReflectionClass(get_called_class());
        $methods = $reflectionClass->getMethods(ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PUBLIC);    
        $className = get_called_class();

        foreach($methods as $method)
        {
            if ($method->class === $className)
            {
                $enumItem = $method->invoke(null);

                if ($enumItem instanceof $className && $enumItem->$getter() === $value)
                {
                    return $enumItem;
                }
            }
        }

        throw new OutOfRangeException();
    }

    protected static function _create($value)
    {
        if (self::$_instancedValues === null)
        {
            self::$_instancedValues = array();
        }

        $className = get_called_class();

        if (!isset(self::$_instancedValues[$className]))
        {
            self::$_instancedValues[$className] = array();
        }

        if (!isset(self::$_instancedValues[$className][$value]))
        {
            $debugTrace = debug_backtrace();
            $lastCaller = array_shift($debugTrace);

            while ($lastCaller['class'] !== $className && count($debugTrace) > 0)
            {
                $lastCaller = array_shift($debugTrace);
            }

            self::$_instancedValues[$className][$value] = new static($value, $lastCaller['function']);
        }

        return self::$_instancedValues[$className][$value];
    }

    public static function fromValue($value)
    {
        return self::_fromGetter('getValue', $value);
    }

    public static function fromName($value)
    {
        return self::_fromGetter('getName', $value);
    }

    public function getValue()
    {
        return $this->_value;
    }

    public function getName()
    {
        return $this->_name;
    }
}

Ví dụ Enum:

final class DaysOfWeek extends TypedEnum
{
    public static function Sunday() { return self::_create(0); }    
    public static function Monday() { return self::_create(1); }
    public static function Tuesday() { return self::_create(2); }   
    public static function Wednesday() { return self::_create(3); }
    public static function Thursday() { return self::_create(4); }  
    public static function Friday() { return self::_create(5); }
    public static function Saturday() { return self::_create(6); }      
}

Ví dụ sử dụng:

function saveEvent(DaysOfWeek $weekDay, $comment)
{
    // store week day numeric value and comment:
    $myDatabase->save('myeventtable', 
       array('weekday_id' => $weekDay->getValue()),
       array('comment' => $comment));
}

// call the function, note: DaysOfWeek::Monday() returns an object of type DaysOfWeek
saveEvent(DaysOfWeek::Monday(), 'some comment');

Lưu ý rằng tất cả các phiên bản của cùng một mục enum đều giống nhau:

$monday1 = DaysOfWeek::Monday();
$monday2 = DaysOfWeek::Monday();
$monday1 === $monday2; // true

Bạn cũng có thể sử dụng nó bên trong câu lệnh switch:

function getGermanWeekDayName(DaysOfWeek $weekDay)
{
    switch ($weekDay)
    {
        case DaysOfWeek::Monday(): return 'Montag';
        case DaysOfWeek::Tuesday(): return 'Dienstag';
        // ...
}

Bạn cũng có thể tạo một mục enum theo tên hoặc giá trị:

$monday = DaysOfWeek::fromValue(2);
$tuesday = DaysOfWeek::fromName('Tuesday');

Hoặc bạn chỉ có thể lấy tên (tức là tên hàm) từ mục nhập enum hiện có:

$wednesday = DaysOfWeek::Wednesday()
echo $wednesDay->getName(); // Wednesday

+1 cho một nhà xây dựng tư nhân. Tôi sẽ không tạo ra lớp trừu tượng của người trợ giúp, chỉ là một lớp đơn giản, nhà xây dựng riêng và một sốconst Monday = DaysOfWeek('Monday');
Kangur

9

Tôi tìm thấy thư viện này trên github và tôi nghĩ rằng nó cung cấp một sự thay thế rất hợp lý cho các câu trả lời ở đây.

Triển khai PHP Enum lấy cảm hứng từ SplEnum

  • Bạn có thể gõ gợi ý: function setAction(Action $action) {
  • Bạn có thể làm phong phú thêm enum với các phương pháp (ví dụ format, parse...)
  • Bạn có thể mở rộng enum để thêm các giá trị mới (tạo enum của bạn finalđể ngăn chặn nó)
  • Bạn có thể nhận được một danh sách tất cả các giá trị có thể (xem bên dưới)

Tờ khai

<?php
use MyCLabs\Enum\Enum;

/**
 * Action enum
 */
class Action extends Enum
{
    const VIEW = 'view';
    const EDIT = 'edit';
}

Sử dụng

<?php
$action = new Action(Action::VIEW);

// or
$action = Action::VIEW();

loại giá trị enum gợi ý:

<?php
function setAction(Action $action) {
    // ...
}

1
Đây là câu trả lời đúng (hiện tại, cho đến khi enumđược thêm vào PHP 7.x) vì nó cho phép gợi ý kiểu.
Tobia

1
Điều này không chỉ cho phép gợi ý kiểu, mà vì __toString()phép thuật, nó cho phép bạn thực hiện những gì bạn thường thực sự muốn với enums - sử dụng chúng trong một câu lệnh switchhoặc ifso sánh trực tiếp với các giá trị của các hằng số. Cách tiếp cận tốt nhất ngắn về hỗ trợ enum bản địa, IMO.
LinusR

7

Nếu bạn cần sử dụng các enum là duy nhất trên toàn cầu (nghĩa là ngay cả khi so sánh các yếu tố giữa các Enums khác nhau) và dễ sử dụng, hãy sử dụng mã sau đây. Tôi cũng đã thêm một số phương pháp mà tôi thấy hữu ích. Bạn sẽ tìm thấy các ví dụ trong các bình luận ở đầu mã.

<?php

/**
 * Class Enum
 * 
 * @author Christopher Fox <christopher.fox@gmx.de>
 *
 * @version 1.0
 *
 * This class provides the function of an enumeration.
 * The values of Enum elements are unique (even between different Enums)
 * as you would expect them to be.
 *
 * Constructing a new Enum:
 * ========================
 *
 * In the following example we construct an enum called "UserState"
 * with the elements "inactive", "active", "banned" and "deleted".
 * 
 * <code>
 * Enum::Create('UserState', 'inactive', 'active', 'banned', 'deleted');
 * </code>
 *
 * Using Enums:
 * ============
 *
 * The following example demonstrates how to compare two Enum elements
 *
 * <code>
 * var_dump(UserState::inactive == UserState::banned); // result: false
 * var_dump(UserState::active == UserState::active); // result: true
 * </code>
 *
 * Special Enum methods:
 * =====================
 *
 * Get the number of elements in an Enum:
 *
 * <code>
 * echo UserState::CountEntries(); // result: 4
 * </code>
 *
 * Get a list with all elements of the Enum:
 *
 * <code>
 * $allUserStates = UserState::GetEntries();
 * </code>
 *
 * Get a name of an element:
 *
 * <code>
 * echo UserState::GetName(UserState::deleted); // result: deleted
 * </code>
 *
 * Get an integer ID for an element (e.g. to store as a value in a database table):
 * This is simply the index of the element (beginning with 1).
 * Note that this ID is only unique for this Enum but now between different Enums.
 *
 * <code>
 * echo UserState::GetDatabaseID(UserState::active); // result: 2
 * </code>
 */
class Enum
{

    /**
     * @var Enum $instance The only instance of Enum (Singleton)
     */
    private static $instance;

    /**
     * @var array $enums    An array of all enums with Enum names as keys
     *          and arrays of element names as values
     */
    private $enums;

    /**
     * Constructs (the only) Enum instance
     */
    private function __construct()
    {
        $this->enums = array();
    }

    /**
     * Constructs a new enum
     *
     * @param string $name The class name for the enum
     * @param mixed $_ A list of strings to use as names for enum entries
     */
    public static function Create($name, $_)
    {
        // Create (the only) Enum instance if this hasn't happened yet
        if (self::$instance===null)
        {
            self::$instance = new Enum();
        }

        // Fetch the arguments of the function
        $args = func_get_args();
        // Exclude the "name" argument from the array of function arguments,
        // so only the enum element names remain in the array
        array_shift($args);
        self::$instance->add($name, $args);
    }

    /**
     * Creates an enumeration if this hasn't happened yet
     * 
     * @param string $name The class name for the enum
     * @param array $fields The names of the enum elements
     */
    private function add($name, $fields)
    {
        if (!array_key_exists($name, $this->enums))
        {
            $this->enums[$name] = array();

            // Generate the code of the class for this enumeration
            $classDeclaration =     "class " . $name . " {\n"
                        . "private static \$name = '" . $name . "';\n"
                        . $this->getClassConstants($name, $fields)
                        . $this->getFunctionGetEntries($name)
                        . $this->getFunctionCountEntries($name)
                        . $this->getFunctionGetDatabaseID()
                        . $this->getFunctionGetName()
                        . "}";

            // Create the class for this enumeration
            eval($classDeclaration);
        }
    }

    /**
     * Returns the code of the class constants
     * for an enumeration. These are the representations
     * of the elements.
     * 
     * @param string $name The class name for the enum
     * @param array $fields The names of the enum elements
     *
     * @return string The code of the class constants
     */
    private function getClassConstants($name, $fields)
    {
        $constants = '';

        foreach ($fields as $field)
        {
            // Create a unique ID for the Enum element
            // This ID is unique because class and variables
            // names can't contain a semicolon. Therefore we
            // can use the semicolon as a separator here.
            $uniqueID = $name . ";" . $field;
            $constants .=   "const " . $field . " = '". $uniqueID . "';\n";
            // Store the unique ID
            array_push($this->enums[$name], $uniqueID);
        }

        return $constants;
    }

    /**
     * Returns the code of the function "GetEntries()"
     * for an enumeration
     * 
     * @param string $name The class name for the enum
     *
     * @return string The code of the function "GetEntries()"
     */
    private function getFunctionGetEntries($name) 
    {
        $entryList = '';        

        // Put the unique element IDs in single quotes and
        // separate them with commas
        foreach ($this->enums[$name] as $key => $entry)
        {
            if ($key > 0) $entryList .= ',';
            $entryList .= "'" . $entry . "'";
        }

        return  "public static function GetEntries() { \n"
            . " return array(" . $entryList . ");\n"
            . "}\n";
    }

    /**
     * Returns the code of the function "CountEntries()"
     * for an enumeration
     * 
     * @param string $name The class name for the enum
     *
     * @return string The code of the function "CountEntries()"
     */
    private function getFunctionCountEntries($name) 
    {
        // This function will simply return a constant number (e.g. return 5;)
        return  "public static function CountEntries() { \n"
            . " return " . count($this->enums[$name]) . ";\n"
            . "}\n";
    }

    /**
     * Returns the code of the function "GetDatabaseID()"
     * for an enumeration
     * 
     * @return string The code of the function "GetDatabaseID()"
     */
    private function getFunctionGetDatabaseID()
    {
        // Check for the index of this element inside of the array
        // of elements and add +1
        return  "public static function GetDatabaseID(\$entry) { \n"
            . "\$key = array_search(\$entry, self::GetEntries());\n"
            . " return \$key + 1;\n"
            . "}\n";
    }

    /**
     * Returns the code of the function "GetName()"
     * for an enumeration
     *
     * @return string The code of the function "GetName()"
     */
    private function getFunctionGetName()
    {
        // Remove the class name from the unique ID 
        // and return this value (which is the element name)
        return  "public static function GetName(\$entry) { \n"
            . "return substr(\$entry, strlen(self::\$name) + 1 , strlen(\$entry));\n"
            . "}\n";
    }

}


?>

1
Tôi làm như thế này, rất nhiều. Tuy nhiên, một trong những phàn nàn chính là khả năng IDE nhận các giá trị để tự động hoàn thành. Tôi không chắc điều này sẽ có thể làm điều đó mà không cần một addon tùy chỉnh cho IDE. Không phải là nó không thể được thực hiện, nó sẽ mất một số công việc.
corsiKa

2
eval()Chỉ sử dụng để bạn có thể khai báo thời gian chạy Enums mới? Eek. Tôi không cảm thấy nó. Làm thế nào để bạn ngăn các lớp khác tạo một lớp Enum không chính xác trước khi bạn xác định đúng lớp? Không phải là Enums được biết trước khi chạy? Và như @corsiKa ngụ ý, không có tự động hoàn thành IDE. Chỉ có lợi ích tôi thấy là lười viết mã.
KrekkieD

7

Tôi cũng thích enum từ java và vì lý do này, tôi viết enum của mình theo cách này, tôi nghĩ rằng đây là cách xử lý tương tự như trong enums Java, tất nhiên, nếu một số người muốn sử dụng nhiều phương thức hơn từ java nên viết nó ở đây hoặc trong lớp trừu tượng nhưng ý tưởng cốt lõi được nhúng trong mã dưới đây


class FruitsEnum {

    static $APPLE = null;
    static $ORANGE = null;

    private $value = null;

    public static $map;

    public function __construct($value) {
        $this->value = $value;
    }

    public static function init () {
        self::$APPLE  = new FruitsEnum("Apple");
        self::$ORANGE = new FruitsEnum("Orange");
        //static map to get object by name - example Enum::get("INIT") - returns Enum::$INIT object;
        self::$map = array (
            "Apple" => self::$APPLE,
            "Orange" => self::$ORANGE
        );
    }

    public static function get($element) {
        if($element == null)
            return null;
        return self::$map[$element];
    }

    public function getValue() {
        return $this->value;
    }

    public function equals(FruitsEnum $element) {
        return $element->getValue() == $this->getValue();
    }

    public function __toString () {
        return $this->value;
    }
}
FruitsEnum::init();

var_dump(FruitsEnum::$APPLE->equals(FruitsEnum::$APPLE)); //true
var_dump(FruitsEnum::$APPLE->equals(FruitsEnum::$ORANGE)); //false
var_dump(FruitsEnum::$APPLE instanceof FruitsEnum); //true
var_dump(FruitsEnum::get("Apple")->equals(FruitsEnum::$APPLE)); //true - enum from string
var_dump(FruitsEnum::get("Apple")->equals(FruitsEnum::get("Orange"))); //false

3
Tôi đang làm khá nhiều điều tương tự, với hai bổ sung nhỏ: Tôi đã ẩn các giá trị tĩnh đằng sau các getters tĩnh. Một lý do là, tôi trực quan thích FruitsEnum::Apple()hơn FruitsEnum::$Apple, nhưng lý do quan trọng hơn là để ngăn chặn bất kỳ ai khác thiết lập $APPLE, do đó phá vỡ enum cho toàn bộ ứng dụng. Cái còn lại là một cờ tĩnh riêng tư đơn giản $initializedđể đảm bảo rằng cuộc gọi init()trở thành không hoạt động sau khi gọi nó lần đầu tiên (vì vậy không ai có thể gây rối với điều đó).
Martin Ender

Tôi đã thích Martin. .init()là lạ, và tôi không quan tâm đến cách tiếp cận getter.
Sebas

7
abstract class Enumeration
{
    public static function enum() 
    {
        $reflect = new ReflectionClass( get_called_class() );
        return $reflect->getConstants();
    }
}


class Test extends Enumeration
{
    const A = 'a';
    const B = 'b';    
}


foreach (Test::enum() as $key => $value) {
    echo "$key -> $value<br>";
}


5

Giải pháp phổ biến nhất mà tôi đã thấy đối với enum là trong PHP là tạo một lớp enum chung và sau đó mở rộng nó. Bạn có thể xem cái này .

CẬP NHẬT: Ngoài ra, tôi tìm thấy điều này từ phpgroupes.org.


1
Mặc dù việc triển khai rất khó khăn và có thể sẽ thực hiện được công việc, nhưng nhược điểm của điều này là các IDE có thể không biết cách tự động điền vào các enum. Tôi không thể kiểm tra cái này từ phpgroupes.org, vì nó muốn tôi đăng ký.
Henrik Paul

5

Đây là một thư viện github để xử lý các kiểu liệt kê an toàn trong php:

Thư viện này xử lý việc tạo các lớp, lưu trữ các lớp và nó thực hiện mẫu thiết kế Kiểu liệt kê an toàn, với một số phương thức trợ giúp để xử lý các enum, như lấy ra một thứ tự để sắp xếp enum hoặc lấy ra một giá trị nhị phân, cho các kết hợp enum.

Mã được tạo sử dụng tệp mẫu php cũ đơn giản, cũng có thể định cấu hình được, do đó bạn có thể cung cấp mẫu của riêng mình.

Đây là bài kiểm tra đầy đủ với phpunit.

php-enums trên github (cứ tự nhiên rẽ nhánh)

Cách sử dụng: (@see used.php hoặc kiểm tra đơn vị để biết thêm chi tiết)

<?php
//require the library
require_once __DIR__ . '/src/Enum.func.php';

//if you don't have a cache directory, create one
@mkdir(__DIR__ . '/cache');
EnumGenerator::setDefaultCachedClassesDir(__DIR__ . '/cache');

//Class definition is evaluated on the fly:
Enum('FruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'));

//Class definition is cached in the cache directory for later usage:
Enum('CachedFruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'), '\my\company\name\space', true);

echo 'FruitsEnum::APPLE() == FruitsEnum::APPLE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::APPLE()) . "\n";

echo 'FruitsEnum::APPLE() == FruitsEnum::ORANGE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::ORANGE()) . "\n";

echo 'FruitsEnum::APPLE() instanceof Enum: ';
var_dump(FruitsEnum::APPLE() instanceof Enum) . "\n";

echo 'FruitsEnum::APPLE() instanceof FruitsEnum: ';
var_dump(FruitsEnum::APPLE() instanceof FruitsEnum) . "\n";

echo "->getName()\n";
foreach (FruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getName() . "\n";
}

echo "->getValue()\n";
foreach (FruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getValue() . "\n";
}

echo "->getOrdinal()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getOrdinal() . "\n";
}

echo "->getBinary()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getBinary() . "\n";
}

Đầu ra:

FruitsEnum::APPLE() == FruitsEnum::APPLE(): bool(true)
FruitsEnum::APPLE() == FruitsEnum::ORANGE(): bool(false)
FruitsEnum::APPLE() instanceof Enum: bool(true)
FruitsEnum::APPLE() instanceof FruitsEnum: bool(true)
->getName()
  APPLE
  ORANGE
  RASBERRY
  BANNANA
->getValue()
  apple
  orange
  rasberry
  bannana
->getValue() when values have been specified
  pig
  dog
  cat
  bird
->getOrdinal()
  1
  2
  3
  4
->getBinary()
  1
  2
  4
  8

4

Tôi đã sử dụng cách tiếp cận dưới đây vì nó mang lại cho tôi khả năng có loại an toàn cho các tham số chức năng, tự động hoàn thành trong NetBeans và hiệu suất tốt. Một điều tôi không thích quá nhiều là bạn phải gọi [extended class name]::enumerate();sau khi xác định lớp.

abstract class Enum {

    private $_value;

    protected function __construct($value) {
        $this->_value = $value;
    }

    public function __toString() {
        return (string) $this->_value;
    }

    public static function enumerate() {
        $class = get_called_class();
        $ref = new ReflectionClass($class);
        $statics = $ref->getStaticProperties();
        foreach ($statics as $name => $value) {
            $ref->setStaticPropertyValue($name, new $class($value));
        }
    }
}

class DaysOfWeek extends Enum {
    public static $MONDAY = 0;
    public static $SUNDAY = 1;
    // etc.
}
DaysOfWeek::enumerate();

function isMonday(DaysOfWeek $d) {
    if ($d == DaysOfWeek::$MONDAY) {
        return true;
    } else {
        return false;
    }
}

$day = DaysOfWeek::$MONDAY;
echo (isMonday($day) ? "bummer it's monday" : "Yay! it's not monday");

Không có gì ngăn cản bạn xác định lại các giá trị enum:DaysOfWeek::$MONDAY = 3;
KrekkieD

@BrianFisher, tôi biết đó là một nit muộn, nhưng, nếu bạn không thích gọi [extended class name]::enumerate();theo định nghĩa, tại sao bạn không làm điều đó trong cấu trúc?
Có thể O 'Spam

4

Định nghĩa lớp Enum của tôi dưới đây được gõ mạnh mẽ , và rất tự nhiên để sử dụng và định nghĩa.

Định nghĩa:

class Fruit extends Enum {
    static public $APPLE = 1;
    static public $ORANGE = 2;
}
Fruit::initialize(); //Can also be called in autoloader

Chuyển qua Enum

$myFruit = Fruit::$APPLE;

switch ($myFruit) {
    case Fruit::$APPLE  : echo "I like apples\n";  break;
    case Fruit::$ORANGE : echo "I hate oranges\n"; break;
}

>> I like apples

Truyền Enum làm tham số (Đánh máy mạnh)

/** Function only accepts Fruit enums as input**/
function echoFruit(Fruit $fruit) {
    echo $fruit->getName().": ".$fruit->getValue()."\n";
}

/** Call function with each Enum value that Fruit has */
foreach (Fruit::getList() as $fruit) {
    echoFruit($fruit);
}

//Call function with Apple enum
echoFruit(Fruit::$APPLE)

//Will produce an error. This solution is strongly typed
echoFruit(2);

>> APPLE: 1
>> ORANGE: 2
>> APPLE: 1
>> Argument 1 passed to echoFruit() must be an instance of Fruit, integer given

Echo Enum dưới dạng chuỗi

echo "I have an $myFruit\n";

>> I have an APPLE

Nhận Enum theo số nguyên

$myFruit = Fruit::getByValue(2);

echo "Now I have an $myFruit\n";

>> Now I have an ORANGE

Nhận Enum bằng tên

$myFruit = Fruit::getByName("APPLE");

echo "But I definitely prefer an $myFruit\n\n";

>> But I definitely prefer an APPLE

Lớp Enum:

/**
 * @author Torge Kummerow
 */
class Enum {

    /**
     * Holds the values for each type of Enum
     */
    static private $list = array();

    /**
     * Initializes the enum values by replacing the number with an instance of itself
     * using reflection
     */
    static public function initialize() {
        $className = get_called_class();
        $class = new ReflectionClass($className);
        $staticProperties = $class->getStaticProperties();

        self::$list[$className] = array();

        foreach ($staticProperties as $propertyName => &$value) {
            if ($propertyName == 'list')
                continue;

            $enum = new $className($propertyName, $value);
            $class->setStaticPropertyValue($propertyName, $enum);
            self::$list[$className][$propertyName] = $enum;
        } unset($value);
    }


    /**
     * Gets the enum for the given value
     *
     * @param integer $value
     * @throws Exception
     *
     * @return Enum
     */
    static public function getByValue($value) {
        $className = get_called_class();
        foreach (self::$list[$className] as $propertyName=>&$enum) {
            /* @var $enum Enum */
            if ($enum->value == $value)
                return $enum;
        } unset($enum);

        throw new Exception("No such enum with value=$value of type ".get_called_class());
    }

    /**
     * Gets the enum for the given name
     *
     * @param string $name
     * @throws Exception
     *
     * @return Enum
     */
    static public function getByName($name) {
        $className = get_called_class();
        if (array_key_exists($name, static::$list[$className]))
            return self::$list[$className][$name];

        throw new Exception("No such enum ".get_called_class()."::\$$name");
    }


    /**
     * Returns the list of all enum variants
     * @return Array of Enum
     */
    static public function getList() {
        $className = get_called_class();
        return self::$list[$className];
    }


    private $name;
    private $value;

    public function __construct($name, $value) {
        $this->name = $name;
        $this->value = $value;
    }

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

    public function getValue() {
        return $this->value;
    }

    public function getName() {
        return $this->name;
    }

}

Thêm vào

Bạn cũng có thể thêm ý kiến ​​cho IDE

class Fruit extends Enum {

    /**
     * This comment is for autocomplete support in common IDEs
     * @var Fruit A yummy apple
     */
    static public $APPLE = 1;

    /**
     * This comment is for autocomplete support in common IDEs
     * @var Fruit A sour orange
     */
    static public $ORANGE = 2;
}

//This can also go to the autoloader if available.
Fruit::initialize();

4

Tôi nhận ra đây là một chủ đề rất rất cũ nhưng tôi đã có suy nghĩ về điều này và muốn biết mọi người nghĩ gì.

Ghi chú: Tôi đã chơi xung quanh với điều này và nhận ra rằng nếu tôi chỉ sửa đổi __call() chức năng mà bạn có thể tiến gần hơn đến thực tế enums. Các __call()chức năng xử lý tất cả các cuộc gọi chức năng chưa biết. Vì vậy, giả sử bạn muốn tạo ba enumsRED_LIGHT, YELLOW_LIGHT và GREEN_LIGHT. Bây giờ bạn có thể làm như vậy bằng cách làm như sau:

$c->RED_LIGHT();
$c->YELLOW_LIGHT();
$c->GREEN_LIGHT();

Sau khi xác định tất cả những gì bạn phải làm là gọi lại cho họ để nhận các giá trị:

echo $c->RED_LIGHT();
echo $c->YELLOW_LIGHT();
echo $c->GREEN_LIGHT();

và bạn sẽ nhận được 0, 1 và 2. Hãy vui vẻ! Điều này hiện cũng đã có trên GitHub.

Cập nhật: Tôi đã làm cho nó cả __get()__set() chức năng và chức năng hiện đang được sử dụng. Điều này cho phép bạn không phải gọi một chức năng trừ khi bạn muốn. Thay vào đó, bây giờ bạn chỉ có thể nói:

$c->RED_LIGHT;
$c->YELLOW_LIGHT;
$c->GREEN_LIGHT;

Đối với cả việc tạo và nhận các giá trị. Bởi vì các biến không được xác định ban đầu,__get() hàm được gọi (vì không có giá trị được chỉ định) cho thấy mục nhập trong mảng chưa được tạo. Vì vậy, nó tạo ra mục nhập, gán cho nó giá trị cuối cùng được cộng với một (+1), tăng biến giá trị cuối cùng và trả về TRUE. Nếu bạn đặt giá trị:

$c->RED_LIGHT = 85;

Sau đó, __set()hàm được gọi và giá trị cuối cùng được đặt thành giá trị mới cộng với một (+1). Vì vậy, bây giờ chúng tôi có một cách khá tốt để làm enum và chúng có thể được tạo ra một cách nhanh chóng.

<?php
################################################################################
#   Class ENUMS
#
#       Original code by Mark Manning.
#       Copyrighted (c) 2015 by Mark Manning.
#       All rights reserved.
#
#       This set of code is hereby placed into the free software universe
#       via the GNU greater license thus placing it under the Copyleft
#       rules and regulations with the following modifications:
#
#       1. You may use this work in any other work.  Commercial or otherwise.
#       2. You may make as much money as you can with it.
#       3. You owe me nothing except to give me a small blurb somewhere in
#           your program or maybe have pity on me and donate a dollar to
#           sim_sales@paypal.com.  :-)
#
#   Blurb:
#
#       PHP Class Enums by Mark Manning (markem-AT-sim1-DOT-us).
#       Used with permission.
#
#   Notes:
#
#       VIM formatting.  Set tabs to four(4) spaces.
#
################################################################################
class enums
{
    private $enums;
    private $clear_flag;
    private $last_value;

################################################################################
#   __construct(). Construction function.  Optionally pass in your enums.
################################################################################
function __construct()
{
    $this->enums = array();
    $this->clear_flag = false;
    $this->last_value = 0;

    if( func_num_args() > 0 ){
        return $this->put( func_get_args() );
        }

    return true;
}
################################################################################
#   put(). Insert one or more enums.
################################################################################
function put()
{
    $args = func_get_args();
#
#   Did they send us an array of enums?
#   Ex: $c->put( array( "a"=>0, "b"=>1,...) );
#   OR  $c->put( array( "a", "b", "c",... ) );
#
    if( is_array($args[0]) ){
#
#   Add them all in
#
        foreach( $args[0] as $k=>$v ){
#
#   Don't let them change it once it is set.
#   Remove the IF statement if you want to be able to modify the enums.
#
            if( !isset($this->enums[$k]) ){
#
#   If they sent an array of enums like this: "a","b","c",... then we have to
#   change that to be "A"=>#. Where "#" is the current count of the enums.
#
                if( is_numeric($k) ){
                    $this->enums[$v] = $this->last_value++;
                    }
#
#   Else - they sent "a"=>"A", "b"=>"B", "c"=>"C"...
#
                    else {
                        $this->last_value = $v + 1;
                        $this->enums[$k] = $v;
                        }
                }
            }
        }
#
#   Nope!  Did they just sent us one enum?
#
        else {
#
#   Is this just a default declaration?
#   Ex: $c->put( "a" );
#
            if( count($args) < 2 ){
#
#   Again - remove the IF statement if you want to be able to change the enums.
#
                if( !isset($this->enums[$args[0]]) ){
                    $this->enums[$args[0]] = $this->last_value++;
                    }
#
#   No - they sent us a regular enum
#   Ex: $c->put( "a", "This is the first enum" );
#
                    else {
#
#   Again - remove the IF statement if you want to be able to change the enums.
#
                        if( !isset($this->enums[$args[0]]) ){
                            $this->last_value = $args[1] + 1;
                            $this->enums[$args[0]] = $args[1];
                            }
                        }
                }
            }

    return true;
}
################################################################################
#   get(). Get one or more enums.
################################################################################
function get()
{
    $num = func_num_args();
    $args = func_get_args();
#
#   Is this an array of enums request? (ie: $c->get(array("a","b","c"...)) )
#
    if( is_array($args[0]) ){
        $ary = array();
        foreach( $args[0] as $k=>$v ){
            $ary[$v] = $this->enums[$v];
            }

        return $ary;
        }
#
#   Is it just ONE enum they want? (ie: $c->get("a") )
#
        else if( ($num > 0) && ($num < 2) ){
            return $this->enums[$args[0]];
            }
#
#   Is it a list of enums they want? (ie: $c->get( "a", "b", "c"...) )
#
        else if( $num > 1 ){
            $ary = array();
            foreach( $args as $k=>$v ){
                $ary[$v] = $this->enums[$v];
                }

            return $ary;
            }
#
#   They either sent something funky or nothing at all.
#
    return false;
}
################################################################################
#   clear(). Clear out the enum array.
#       Optional.  Set the flag in the __construct function.
#       After all, ENUMS are supposed to be constant.
################################################################################
function clear()
{
    if( $clear_flag ){
        unset( $this->enums );
        $this->enums = array();
        }

    return true;
}
################################################################################
#   __call().  In case someone tries to blow up the class.
################################################################################
function __call( $name, $arguments )
{
    if( isset($this->enums[$name]) ){ return $this->enums[$name]; }
        else if( !isset($this->enums[$name]) && (count($arguments) > 0) ){
            $this->last_value = $arguments[0] + 1;
            $this->enums[$name] = $arguments[0];
            return true;
            }
        else if( !isset($this->enums[$name]) && (count($arguments) < 1) ){
            $this->enums[$name] = $this->last_value++;
            return true;
            }

    return false;
}
################################################################################
#   __get(). Gets the value.
################################################################################
function __get($name)
{
    if( isset($this->enums[$name]) ){ return $this->enums[$name]; }
        else if( !isset($this->enums[$name]) ){
            $this->enums[$name] = $this->last_value++;
            return true;
            }

    return false;
}
################################################################################
#   __set().  Sets the value.
################################################################################
function __set( $name, $value=null )
{
    if( isset($this->enums[$name]) ){ return false; }
        else if( !isset($this->enums[$name]) && !is_null($value) ){
            $this->last_value = $value + 1;
            $this->enums[$name] = $value;
            return true;
            }
        else if( !isset($this->enums[$name]) && is_null($value) ){
            $this->enums[$name] = $this->last_value++;
            return true;
            }

    return false;
}
################################################################################
#   __destruct().  Deconstruct the class.  Remove the list of enums.
################################################################################
function __destruct()
{
    unset( $this->enums );
    $this->enums = null;

    return true;
}

}
#
#   Test code
#
#   $c = new enums();
#   $c->RED_LIGHT(85);
#   $c->YELLOW_LIGHT = 23;
#   $c->GREEN_LIGHT;
#
#   echo $c->RED_LIGHT . "\n";
#   echo $c->YELLOW_LIGHT . "\n";
#   echo $c->GREEN_LIGHT . "\n";

?>

3

Tôi biết đây là một chủ đề cũ, tuy nhiên không có cách giải quyết nào tôi thấy thực sự trông giống như enum, vì hầu như tất cả các cách giải quyết đều yêu cầu bạn gán giá trị thủ công cho các mục enum hoặc nó yêu cầu bạn chuyển một mảng các khóa enum cho chức năng. Vì vậy, tôi đã tạo ra giải pháp của riêng tôi cho việc này.

Để tạo một lớp enum bằng giải pháp của tôi, người ta có thể chỉ cần mở rộng lớp Enum bên dưới, tạo một loạt các biến tĩnh (không cần khởi tạo chúng) và thực hiện cuộc gọi đến yourEnumClass :: init () ngay bên dưới định nghĩa của lớp enum của bạn .

chỉnh sửa: Điều này chỉ hoạt động trong php> = 5.3, nhưng nó có thể được sửa đổi để hoạt động trong các phiên bản cũ hơn

/**
 * A base class for enums. 
 * 
 * This class can be used as a base class for enums. 
 * It can be used to create regular enums (incremental indices), but it can also be used to create binary flag values.
 * To create an enum class you can simply extend this class, and make a call to <yourEnumClass>::init() before you use the enum.
 * Preferably this call is made directly after the class declaration. 
 * Example usages:
 * DaysOfTheWeek.class.php
 * abstract class DaysOfTheWeek extends Enum{
 *      static $MONDAY = 1;
 *      static $TUESDAY;
 *      static $WEDNESDAY;
 *      static $THURSDAY;
 *      static $FRIDAY;
 *      static $SATURDAY;
 *      static $SUNDAY;
 * }
 * DaysOfTheWeek::init();
 * 
 * example.php
 * require_once("DaysOfTheWeek.class.php");
 * $today = date('N');
 * if ($today == DaysOfTheWeek::$SUNDAY || $today == DaysOfTheWeek::$SATURDAY)
 *      echo "It's weekend!";
 * 
 * Flags.class.php
 * abstract class Flags extends Enum{
 *      static $FLAG_1;
 *      static $FLAG_2;
 *      static $FLAG_3;
 * }
 * Flags::init(Enum::$BINARY_FLAG);
 * 
 * example2.php
 * require_once("Flags.class.php");
 * $flags = Flags::$FLAG_1 | Flags::$FLAG_2;
 * if ($flags & Flags::$FLAG_1)
 *      echo "Flag_1 is set";
 * 
 * @author Tiddo Langerak
 */
abstract class Enum{

    static $BINARY_FLAG = 1;
    /**
     * This function must be called to initialize the enumeration!
     * 
     * @param bool $flags If the USE_BINARY flag is provided, the enum values will be binary flag values. Default: no flags set.
     */ 
    public static function init($flags = 0){
        //First, we want to get a list of all static properties of the enum class. We'll use the ReflectionClass for this.
        $enum = get_called_class();
        $ref = new ReflectionClass($enum);
        $items = $ref->getStaticProperties();
        //Now we can start assigning values to the items. 
        if ($flags & self::$BINARY_FLAG){
            //If we want binary flag values, our first value should be 1.
            $value = 1;
            //Now we can set the values for all items.
            foreach ($items as $key=>$item){
                if (!isset($item)){                 
                    //If no value is set manually, we should set it.
                    $enum::$$key = $value;
                    //And we need to calculate the new value
                    $value *= 2;
                } else {
                    //If there was already a value set, we will continue starting from that value, but only if that was a valid binary flag value.
                    //Otherwise, we will just skip this item.
                    if ($key != 0 && ($key & ($key - 1) == 0))
                        $value = 2 * $item;
                }
            }
        } else {
            //If we want to use regular indices, we'll start with index 0.
            $value = 0;
            //Now we can set the values for all items.
            foreach ($items as $key=>$item){
                if (!isset($item)){
                    //If no value is set manually, we should set it, and increment the value for the next item.
                    $enum::$$key = $value;
                    $value++;
                } else {
                    //If a value was already set, we'll continue from that value.
                    $value = $item+1;
                }
            }
        }
    }
}

3

Bây giờ bạn có thể sử dụng lớp SplEnum để xây dựng nó nguyên bản. Theo tài liệu chính thức.

SplEnum cung cấp khả năng mô phỏng và tạo các đối tượng liệt kê tự nhiên trong PHP.

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

Xin lưu ý, đây là một tiện ích mở rộng phải được cài đặt, nhưng không có sẵn theo mặc định. Mà thuộc loại đặc biệt được mô tả trong trang web php. Ví dụ trên được lấy từ trang web PHP.


3

Cuối cùng, một câu trả lời PHP 7.1+ với các hằng số không thể bị ghi đè.

/**
 * An interface that groups HTTP Accept: header Media Types in one place.
 */
interface MediaTypes
{
    /**
    * Now, if you have to use these same constants with another class, you can
    * without creating funky inheritance / is-a relationships.
    * Also, this gets around the single inheritance limitation.
    */

    public const HTML = 'text/html';
    public const JSON = 'application/json';
    public const XML = 'application/xml';
    public const TEXT = 'text/plain';
}

/**
 * An generic request class.
 */
abstract class Request
{
    // Why not put the constants here?
    // 1) The logical reuse issue.
    // 2) Single Inheritance. 
    // 3) Overriding is possible.

    // Why put class constants here?
    // 1) The constant value will not be necessary in other class families.
}

/**
 * An incoming / server-side HTTP request class.
 */
class HttpRequest extends Request implements MediaTypes
{
    // This class can implement groups of constants as necessary.
}

Nếu bạn đang sử dụng không gian tên, hoàn thành mã sẽ hoạt động.

Tuy nhiên, khi làm điều này, bạn mất khả năng ẩn các hằng số trong lớp gia đình ( protected) hoặc lớp một mình ( private). Theo định nghĩa, mọi thứ trong một Interfacepublic .

Hướng dẫn sử dụng PHP: Giao diện


Đây không phải là Java. Điều này hoạt động trong trường hợp không yêu cầu mô hình đa hình / Chiến lược để ghi đè các hằng số trong lớp cha.
Anthony Rutledge

2

Đây là sự đảm nhận của tôi về enum "động" ... để tôi có thể gọi nó bằng các biến, ví dụ. từ một hình thức.

nhìn vào bản án được cập nhật bên dưới bộ mã này ...

$value = "concert";
$Enumvalue = EnumCategory::enum($value);
//$EnumValue = 1

class EnumCategory{
    const concert = 1;
    const festival = 2;
    const sport = 3;
    const nightlife = 4;
    const theatre = 5;
    const musical = 6;
    const cinema = 7;
    const charity = 8;
    const museum = 9;
    const other = 10;

    public function enum($string){
        return constant('EnumCategory::'.$string);
    }
}

CẬP NHẬT: Cách tốt hơn để làm điều đó ...

class EnumCategory {

    static $concert = 1;
    static $festival = 2;
    static $sport = 3;
    static $nightlife = 4;
    static $theatre = 5;
    static $musical = 6;
    static $cinema = 7;
    static $charity = 8;
    static $museum = 9;
    static $other = 10;

}

Gọi với

EnumCategory::${$category};

5
Vấn đề với điều này; EnumCategory::$sport = 9;. Chào mừng đến với bảo tàng thể thao. const cách tốt hơn để làm điều đó.
Dan Lugg

2

Câu trả lời được chấp nhận là con đường để đi và thực sự là những gì tôi đang làm cho đơn giản. Hầu hết các lợi thế của liệt kê được cung cấp (có thể đọc, nhanh, vv). Một khái niệm bị thiếu, tuy nhiên: loại an toàn. Trong hầu hết các ngôn ngữ, bảng liệt kê cũng được sử dụng để hạn chế các giá trị được phép. Dưới đây là một ví dụ về cách an toàn kiểu cũng có thể đạt được bằng cách sử dụng các hàm tạo riêng, các phương thức khởi tạo tĩnh và kiểm tra kiểu:

class DaysOfWeek{
 const Sunday = 0;
 const Monday = 1;
 // etc.

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

 //static instantiation methods
 public static function MONDAY(){
   return new self(self::Monday);
 }
 //etc.
}

//function using type checking
function printDayOfWeek(DaysOfWeek $d){ //compiler can now use type checking
  // to something with $d...
}

//calling the function is safe!
printDayOfWeek(DaysOfWeek::MONDAY());

Chúng ta thậm chí có thể đi xa hơn: sử dụng các hằng số trong lớp DaysOfWeek có thể dẫn đến việc sử dụng sai: ví dụ: người ta có thể sử dụng nhầm theo cách này:

printDayOfWeek(DaysOfWeek::Monday); //triggers a compiler error.

đó là sai (gọi hằng số nguyên). Chúng ta có thể ngăn điều này bằng cách sử dụng các biến tĩnh riêng thay vì hằng số:

class DaysOfWeeks{

  private static $monday = 1;
  //etc.

  private $intVal;
  //private constructor
  private function __construct($intVal){
    $this->intVal = $intVal;
  }

  //public instantiation methods
  public static function MONDAY(){
    return new self(self::$monday);
  }
  //etc.


  //convert an instance to its integer value
  public function intVal(){
    return $this->intVal;
  }

}

Tất nhiên, không thể truy cập các hằng số nguyên (đây thực sự là mục đích). Phương thức intVal cho phép chuyển đổi một đối tượng DaysOfWeek thành biểu diễn số nguyên của nó.

Lưu ý rằng chúng ta thậm chí có thể đi xa hơn bằng cách thực hiện cơ chế lưu trữ trong các phương thức khởi tạo để tiết kiệm bộ nhớ trong trường hợp liệt kê được sử dụng rộng rãi ...

Hy vọng điều này sẽ giúp


2

Một số giải pháp tốt ở đây!

Đây là phiên bản của tôi.

  • Nó gõ mạnh
  • Nó hoạt động với IDE tự động hoàn thành
  • Enums được xác định bởi một mã và một mô tả, trong đó mã có thể là một số nguyên, một giá trị nhị phân, một chuỗi ngắn hoặc về cơ bản bất cứ điều gì khác mà bạn muốn. Các mô hình có thể dễ dàng được mở rộng để hỗ trợ các thuộc tính orther.
  • Nó so sánh giá trị (==) và tham chiếu (===) so sánh và hoạt động trong các câu lệnh chuyển đổi.

Tôi nghĩ nhược điểm chính là các thành viên enum phải được khai báo và khởi tạo riêng biệt, do các mô tả và PHP không có khả năng xây dựng các đối tượng tại thời điểm khai báo thành viên tĩnh. Tôi đoán một cách làm tròn điều này có thể là sử dụng sự phản chiếu với các nhận xét tài liệu được phân tích cú pháp thay thế.

Enum trừu tượng trông như thế này:

<?php

abstract class AbstractEnum
{
    /** @var array cache of all enum instances by class name and integer value */
    private static $allEnumMembers = array();

    /** @var mixed */
    private $code;

    /** @var string */
    private $description;

    /**
     * Return an enum instance of the concrete type on which this static method is called, assuming an instance
     * exists for the passed in value.  Otherwise an exception is thrown.
     *
     * @param $code
     * @return AbstractEnum
     * @throws Exception
     */
    public static function getByCode($code)
    {
        $concreteMembers = &self::getConcreteMembers();

        if (array_key_exists($code, $concreteMembers)) {
            return $concreteMembers[$code];
        }

        throw new Exception("Value '$code' does not exist for enum '".get_called_class()."'");
    }

    public static function getAllMembers()
    {
        return self::getConcreteMembers();
    }

    /**
     * Create, cache and return an instance of the concrete enum type for the supplied primitive value.
     *
     * @param mixed $code code to uniquely identify this enum
     * @param string $description
     * @throws Exception
     * @return AbstractEnum
     */
    protected static function enum($code, $description)
    {
        $concreteMembers = &self::getConcreteMembers();

        if (array_key_exists($code, $concreteMembers)) {
            throw new Exception("Value '$code' has already been added to enum '".get_called_class()."'");
        }

        $concreteMembers[$code] = $concreteEnumInstance = new static($code, $description);

        return $concreteEnumInstance;
    }

    /**
     * @return AbstractEnum[]
     */
    private static function &getConcreteMembers() {
        $thisClassName = get_called_class();

        if (!array_key_exists($thisClassName, self::$allEnumMembers)) {
            $concreteMembers = array();
            self::$allEnumMembers[$thisClassName] = $concreteMembers;
        }

        return self::$allEnumMembers[$thisClassName];
    }

    private function __construct($code, $description)
    {
        $this->code = $code;
        $this->description = $description;
    }

    public function getCode()
    {
        return $this->code;
    }

    public function getDescription()
    {
        return $this->description;
    }
}

Dưới đây là một ví dụ cụ thể enum:

<?php

require('AbstractEnum.php');

class EMyEnum extends AbstractEnum
{
    /** @var EMyEnum */
    public static $MY_FIRST_VALUE;
    /** @var EMyEnum */
    public static $MY_SECOND_VALUE;
    /** @var EMyEnum */
    public static $MY_THIRD_VALUE;

    public static function _init()
    {
        self::$MY_FIRST_VALUE = self::enum(1, 'My first value');
        self::$MY_SECOND_VALUE = self::enum(2, 'My second value');
        self::$MY_THIRD_VALUE = self::enum(3, 'My third value');
    }
}

EMyEnum::_init();

Mà có thể được sử dụng như thế này:

<?php

require('EMyEnum.php');

echo EMyEnum::$MY_FIRST_VALUE->getCode().' : '.EMyEnum::$MY_FIRST_VALUE->getDescription().PHP_EOL.PHP_EOL;

var_dump(EMyEnum::getAllMembers());

echo PHP_EOL.EMyEnum::getByCode(2)->getDescription().PHP_EOL;

Và tạo ra đầu ra này:

1: Giá trị đầu tiên của tôi

mảng (3) {
[1] =>
object (EMyEnum) # 1 (2) {
["code": "AbstractEnum": private] =>
int (1)
["description": "AbstractEnum": private] =>
chuỗi (14) "Giá trị đầu tiên của tôi"
}
[2] =>
object (EMyEnum) # 2 (2) {
["code": "AbstractEnum": private] =>
int (2)
["description": "AbstractEnum" : private] =>
chuỗi (15) "Giá trị thứ hai của tôi"
}
[3] =>
object (EMyEnum) # 3 (2) {
["code": "AbstractEnum": private] => chuỗi (14) "Giá trị thứ ba của tôi" } }
int (3)
["mô tả": "Tóm tắtEnum": private] =>


Giá trị thứ hai của tôi


2
class DayOfWeek {
    static $values = array(
        self::MONDAY,
        self::TUESDAY,
        // ...
    );

    const MONDAY  = 0;
    const TUESDAY = 1;
    // ...
}

$today = DayOfWeek::MONDAY;

// If you want to check if a value is valid
assert( in_array( $today, DayOfWeek::$values ) );

Đừng sử dụng sự phản chiếu. Điều này khiến cho việc lập luận về mã của bạn trở nên cực kỳ khó khăn và theo dõi nơi đang sử dụng một cái gì đó và có xu hướng phá vỡ các công cụ phân tích tĩnh (ví dụ: những gì được tích hợp trong IDE của bạn).


2

Một trong những khía cạnh còn thiếu trong một số câu trả lời khác ở đây là cách sử dụng enum với kiểu gợi ý.

Nếu bạn định nghĩa enum của mình là một tập các hằng trong một lớp trừu tượng, vd

abstract class ShirtSize {
    public const SMALL = 1;
    public const MEDIUM = 2;
    public const LARGE = 3;
}

sau đó bạn không thể nhập gợi ý nó trong một tham số chức năng - đối với một, bởi vì nó không thể thực hiện được, mà còn bởi vì kiểu ShirtSize::SMALLnày là int, không phảiShirtSize .

Đó là lý do tại sao các enum bản địa trong PHP sẽ tốt hơn nhiều so với bất cứ điều gì chúng ta có thể nghĩ ra. Tuy nhiên, chúng ta có thể ước tính một enum bằng cách giữ một thuộc tính riêng đại diện cho giá trị của enum, và sau đó hạn chế việc khởi tạo thuộc tính này cho các hằng số được xác định trước của chúng ta. Để ngăn enum được khởi tạo tùy ý (không có chi phí kiểm tra kiểu danh sách trắng), chúng tôi đặt hàm tạo riêng tư.

class ShirtSize {
    private $size;
    private function __construct ($size) {
        $this->size = $size;
    }
    public function equals (ShirtSize $s) {
        return $this->size === $s->size;
    }
    public static function SMALL () { return new self(1); }
    public static function MEDIUM () { return new self(2); }
    public static function LARGE () { return new self(3); }
}

Sau đó chúng ta có thể sử dụng ShirtSizenhư thế này:

function sizeIsAvailable ($productId, ShirtSize $size) {
    // business magic
}
if(sizeIsAvailable($_GET["id"], ShirtSize::LARGE())) {
    echo "Available";
} else {
    echo "Out of stock.";
}
$s2 = ShirtSize::SMALL();
$s3 = ShirtSize::MEDIUM();
echo $s2->equals($s3) ? "SMALL == MEDIUM" : "SMALL != MEDIUM";

Theo cách này, sự khác biệt lớn nhất từ ​​quan điểm của người dùng là bạn phải giải quyết () vấn đề liên tục.

Một nhược điểm là ===(so sánh sự bình đẳng của đối tượng) sẽ trả về false khi ==trả về true. Vì lý do đó, tốt nhất là cung cấp một equalsphương thức, để người dùng không phải nhớ sử dụng ==và không=== so sánh hai giá trị enum.

EDIT: Một vài câu trả lời hiện có rất giống nhau, đặc biệt: https://stackoverflow.com/a/25526473/2407870 .


2

Bước vào câu trả lời của @Brian Cline, tôi nghĩ rằng tôi có thể cho 5 xu của mình

<?php 
/**
 * A class that simulates Enums behaviour
 * <code>
 * class Season extends Enum{
 *    const Spring  = 0;
 *    const Summer = 1;
 *    const Autumn = 2;
 *    const Winter = 3;
 * }
 * 
 * $currentSeason = new Season(Season::Spring);
 * $nextYearSeason = new Season(Season::Spring);
 * $winter = new Season(Season::Winter);
 * $whatever = new Season(-1);               // Throws InvalidArgumentException
 * echo $currentSeason.is(Season::Spring);   // True
 * echo $currentSeason.getName();            // 'Spring'
 * echo $currentSeason.is($nextYearSeason);  // True
 * echo $currentSeason.is(Season::Winter);   // False
 * echo $currentSeason.is(Season::Spring);   // True
 * echo $currentSeason.is($winter);          // False
 * </code>
 * 
 * Class Enum
 * 
 * PHP Version 5.5
 */
abstract class Enum
{
    /**
     * Will contain all the constants of every enum that gets created to 
     * avoid expensive ReflectionClass usage
     * @var array
     */
    private static $_constCacheArray = [];
    /**
     * The value that separates this instance from the rest of the same class
     * @var mixed
     */
    private $_value;
    /**
     * The label of the Enum instance. Will take the string name of the 
     * constant provided, used for logging and human readable messages
     * @var string
     */
    private $_name;
    /**
     * Creates an enum instance, while makes sure that the value given to the 
     * enum is a valid one
     * 
     * @param mixed $value The value of the current
     * 
     * @throws \InvalidArgumentException
     */
    public final function __construct($value)
    {
        $constants = self::_getConstants();
        if (count($constants) !== count(array_unique($constants))) {
            throw new \InvalidArgumentException('Enums cannot contain duplicate constant values');
        }
        if ($name = array_search($value, $constants)) {
            $this->_value = $value;
            $this->_name = $name;
        } else {
            throw new \InvalidArgumentException('Invalid enum value provided');
        }
    }
    /**
     * Returns the constant name of the current enum instance
     * 
     * @return string
     */
    public function getName()
    {
        return $this->_name;
    }
    /**
     * Returns the value of the current enum instance
     * 
     * @return mixed
     */
    public function getValue()
    {
        return $this->_value;
    }
    /**
     * Checks whether this enum instance matches with the provided one.
     * This function should be used to compare Enums at all times instead
     * of an identity comparison 
     * <code>
     * // Assuming EnumObject and EnumObject2 both extend the Enum class
     * // and constants with such values are defined
     * $var  = new EnumObject('test'); 
     * $var2 = new EnumObject('test');
     * $var3 = new EnumObject2('test');
     * $var4 = new EnumObject2('test2');
     * echo $var->is($var2);  // true
     * echo $var->is('test'); // true
     * echo $var->is($var3);  // false
     * echo $var3->is($var4); // false
     * </code>
     * 
     * @param mixed|Enum $enum The value we are comparing this enum object against
     *                         If the value is instance of the Enum class makes
     *                         sure they are instances of the same class as well, 
     *                         otherwise just ensures they have the same value
     * 
     * @return bool
     */
    public final function is($enum)
    {
        // If we are comparing enums, just make
        // sure they have the same toString value
        if (is_subclass_of($enum, __CLASS__)) {
            return get_class($this) === get_class($enum) 
                    && $this->getValue() === $enum->getValue();
        } else {
            // Otherwise assume $enum is the value we are comparing against
            // and do an exact comparison
            return $this->getValue() === $enum;   
        }
    }

    /**
     * Returns the constants that are set for the current Enum instance
     * 
     * @return array
     */
    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];
    }
}

vì một số lý do tôi không thể gọi đây là chức năng. Nó nói với tôi rằng các chức năng như vậy không được khai báo. Tôi đang làm gì sai? [lớp Enum cơ bản nằm trong một tệp khác và tôi đang sử dụng include('enums.php');]. Vì một số lý do, nó không thấy các hàm được khai báo trong Enum cho các lớp con ...
Andrew

Ngoài ra ... làm thế nào để thiết lập nó từ chuỗi? sth like$currentSeason.set("Spring");
Andrew

1

Nỗ lực của tôi để tạo ra một enum với PHP ... nó cực kỳ hạn chế vì nó không hỗ trợ các đối tượng như các giá trị enum nhưng vẫn hơi hữu ích ...

class ProtocolsEnum {

    const HTTP = '1';
    const HTTPS = '2';
    const FTP = '3';

    /**
     * Retrieve an enum value
     * @param string $name
     * @return string
     */
    public static function getValueByName($name) {
        return constant('self::'. $name);
    } 

    /**
     * Retrieve an enum key name
     * @param string $code
     * @return string
     */
    public static function getNameByValue($code) {
        foreach(get_class_constants() as $key => $val) {
            if($val == $code) {
                return $key;
            }
        }
    }

    /**
     * Retrieve associate array of all constants (used for creating droplist options)
     * @return multitype:
     */
    public static function toArray() {      
        return array_flip(self::get_class_constants());
    }

    private static function get_class_constants()
    {
        $reflect = new ReflectionClass(__CLASS__);
        return $reflect->getConstants();
    }
}

nó bị giới hạn ở nhiều hướng và các câu trả lời hiện có cung cấp nhiều hơn nó. Tôi muốn nói rằng điều này không thực sự bổ sung bất cứ điều gì hữu ích.
hakre

1

Hôm qua tôi đã viết lớp này trên blog của tôi . Tôi nghĩ rằng nó có thể dễ sử dụng trong các tập lệnh php:

final class EnumException extends Exception{}

abstract class Enum
{
    /**
     * @var array ReflectionClass
     */
    protected static $reflectorInstances = array();
    /**
     * Массив конфигурированного объекта-константы enum
     * @var array
     */
    protected static $enumInstances = array();
    /**
     * Массив соответствий значение->ключ используется для проверки - 
     * если ли константа с таким значением
     * @var array
     */
    protected static $foundNameValueLink = array();

    protected $constName;
    protected $constValue;

    /**
     * Реализует паттерн "Одиночка"
     * Возвращает объект константы, но но как объект его использовать не стоит, 
     * т.к. для него реализован "волшебный метод" __toString()
     * Это должно использоваться только для типизачии его как параметра
     * @paradm Node
     */
    final public static function get($value)
    {
        // Это остается здесь для увеличения производительности (по замерам ~10%)
        $name = self::getName($value);
        if ($name === false)
            throw new EnumException("Неизвестая константа");
        $className = get_called_class();    
        if (!isset(self::$enumInstances[$className][$name]))
        {
            $value = constant($className.'::'.$name);
            self::$enumInstances[$className][$name] = new $className($name, $value);
        }

        return self::$enumInstances[$className][$name];
    }

    /**
     * Возвращает массив констант пар ключ-значение всего перечисления
     * @return array 
     */
    final public static function toArray()
    {
        $classConstantsArray = self::getReflectorInstance()->getConstants();
        foreach ($classConstantsArray as $k => $v)
            $classConstantsArray[$k] = (string)$v;
        return $classConstantsArray;
    }

    /**
     * Для последующего использования в toArray для получения массива констант ключ->значение 
     * @return ReflectionClass
     */
    final private static function getReflectorInstance()
    {
        $className = get_called_class();
        if (!isset(self::$reflectorInstances[$className]))
        {
            self::$reflectorInstances[$className] = new ReflectionClass($className);
        }
        return self::$reflectorInstances[$className];
    }

    /**
     * Получает имя константы по её значению
     * @param string $value
     */
    final public static function getName($value)
    {
        $className = (string)get_called_class();

        $value = (string)$value;
        if (!isset(self::$foundNameValueLink[$className][$value]))
        {
            $constantName = array_search($value, self::toArray(), true);
            self::$foundNameValueLink[$className][$value] = $constantName;
        }
        return self::$foundNameValueLink[$className][$value];
    }

    /**
     * Используется ли такое имя константы в перечислении
     * @param string $name
     */
    final public static function isExistName($name)
    {
        $constArray = self::toArray();
        return isset($constArray[$name]);
    }

    /**
     * Используется ли такое значение константы в перечислении
     * @param string $value
     */
    final public static function isExistValue($value)
    {
        return self::getName($value) === false ? false : true;
    }   


    final private function __clone(){}

    final private function __construct($name, $value)
    {
        $this->constName = $name;
        $this->constValue = $value;
    }

    final public function __toString()
    {
        return (string)$this->constValue;
    }
}

Sử dụng:

class enumWorkType extends Enum
{
        const FULL = 0;
        const SHORT = 1;
}

2
Nhưng đó là lớp tốt và tên chức năng là bản địa. Và cũng có thể dịch.google.ru có thể giúp đỡ.
Arturgspb

2
Sử dụng kẻ chrome và dịch nó, nếu bạn là lập trình viên, bạn đọc mã!
markus

8
Nói chung, tốt hơn là bao gồm mã trong câu trả lời, thay vì liên kết với tài nguyên bên ngoài có thể có hoặc không có trong 'tháng' / năm, v.v.
John Parker

Lớp học của tôi rất lớn và tôi nghĩ rằng đọc bài đăng này sẽ bất tiện.
Arturgspb

Tôi nghĩ có hai điều tồi tệ ở đây: đó là tiếng Nga (mọi lập trình viên đều phải biết tiếng Anh và sử dụng nó, ngay cả trong các bình luận) & nó không được bao gồm ở đây. Xem trợ giúp làm thế nào để bao gồm mã lớn.
gaRex
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.