PHP ve Numaralandırma


1149

PHP'nin yerel Numaralandırmalar olmadığını biliyorum. Ama Java dünyasından onlara alıştım. Enumları IDE'lerin otomatik tamamlama özelliklerinin anlayabileceği önceden tanımlanmış değerler vermenin bir yolu olarak kullanmak isterim.

Sabitler hile yapmak, ancak orada ad çarpışma problem ve (ya aslında çünkü ) küresel konum. Dizilerin ad alanı sorunu yoktur, ancak çok belirsizdirler, çalışma zamanında üzerine yazılabilirler ve IDE'ler nadiren (asla?) Anahtarlarını otomatik olarak nasıl dolduracaklarını bilirler.

Sık kullandığınız herhangi bir çözüm / geçici çözüm var mı? Herkes PHP adamlar hakkında herhangi bir düşünce ya da karar olup olmadığını hatırlıyor musunuz?



1
Sabitleri bitsel olarak ya da değil olarak numaralandıran bir geçici çözüm işlevi yarattım. Bunu daha önce sorduğunuzu fark
etmediniz


Sabitler sorunu hakkında biraz daha bilgi paylaşmak ister misiniz? "Sabitler hile yapar, ancak ad alanı çarpışma sorunu var ve (veya aslında) küreseller."
XuDing

Yanıtlar:


1492

Kullanım durumuna bağlı olarak, normalde aşağıdaki gibi basit bir şey kullanırdım :

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

$today = DaysOfWeek::Sunday;

Ancak, diğer kullanım durumları sabitlerin ve değerlerin daha fazla doğrulanmasını gerektirebilir. Aşağıdaki yansıma ve diğer birkaç not hakkındaki yorumlara dayanarak, çok daha geniş bir durum yelpazesine daha iyi hizmet edebilecek genişletilmiş bir örnek:

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

BasicEnum'u genişleten basit bir enum sınıfı oluşturarak, artık basit giriş doğrulaması için yöntemleri kullanma olanağına sahipsiniz:

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

Bir yan not olarak, verilerin değişmeyeceği bir statik / const sınıfında (enum gibi) en az bir kez yansımayı kullandığımda, her seferinde taze yansıma nesneleri kullandığım için bu yansıma çağrılarının sonuçlarını önbelleğe alırım sonunda fark edilir bir performans etkisi olacaktır (Birden fazla numaralandırma için bir dizi içinde saklanır).

Artık çoğu insan nihayet en az 5.3'e yükseltti ve SplEnumkullanılabilir, bu da geçerli bir seçenektir - kod tabanınız boyunca gerçek numaralandırma örneklerine sahip olmanın geleneksel olarak kasıtlı olmayan fikrini önemsemediğiniz sürece . Yukarıdaki örnekte, BasicEnumve DaysOfWeekhiçbir şekilde somutlaştırılamaz ve olmamalıdır.


70
Ben de kullanıyorum. Ayrıca sınıfı oluşturmayı da düşünebilirsiniz abstractve finalbu yüzden örneklenemez veya genişletilemez.
ryeguy

21
Bir sınıf hem yapabilirsiniz abstractve final? Java'da buna izin verilmediğini biliyorum. Php bunu yapabilirim?
corsiKa

20
@ryeguy Size bunu yapamaz gibi görünüyor hem abstract ve final. Bu durumda, özet için giderdim.
Nicole

45
Özet veya final hakkında; Onları sonlandırıyorum ve onlara boş bir özel kurucu
veriyorum

21
0 kullanırken dikkatli olun, bu yüzden beklenmedik bir yanlış karşılaştırma problemi ile karşılaşmazsınız, örneğin nullbir switchifadede eşdeğerlik ve arkadaşlarla eşdeğerlik . Orada bulunmak.
yitznewton

185

Yerel bir uzantı da var. SplEnum

SplEnum, PHP'de yerel olarak numaralandırma nesnelerini taklit etme ve oluşturma yeteneği verir.

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

Dikkat:

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

PECL uzantısı PHP ile birlikte verilmez.

Bu PECL uzantısı için bir DLL şu anda kullanılamıyor.


4
İşte splenum ile bir örnek: dreamincode.net/forums/topic/201638-enum-in-php
Nordes

4
Geri döndüm, bağlantıyı görebildiğimde daha çok hoşuma gidiyor. Bana bağlam bilgisi veriyor.
markus

5
Tekrar geri döndüm. Bağlantıyı düzenlemenizi istemiyorum.
markus

6
Bunu kullanırken dikkatli olun. SPL Türleri deneyseldir: "Bu uzantı DENEYSELDİR. Bu uzantının işlevleri ve bu uzantıyı çevreleyen diğer belgeler de dahil olmak üzere davranışı, PHP'nin gelecekteki sürümlerinde önceden haber verilmeksizin değiştirilebilir. Bu uzantı kendi sorumluluğunuzda kullanılmalıdır. "
bzeaman

6
SplEnum PHP ile birlikte gelmez , SPL_Types uzantısına
Kwadz

46

Sınıf sabitleri ne olacak?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

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

echo YourClass::SOME_CONSTANT;

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

Bu basit yaklaşımı tercih ediyorum
David Lemon

echoConstantile değiştirilebilir __toString. Ve sonra sadeceecho $c
Justinas

35

Yukarıdaki en iyi cevap harika. Ancak, extendbunu iki farklı şekilde yaparsanız , ilk olarak hangi uzantı yapılırsa işlev çağrısı önbelleği oluşturur. Bu önbellek daha sonra çağrılar hangi uzantı tarafından başlatılırsa başlasın, sonraki tüm çağrılar tarafından kullanılacaktır ...

Bunu çözmek için, değişkeni ve ilk işlevi aşağıdakiyle değiştirin:

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
Bu sorun vardı. Brian veya düzenleme ayrıcalıklarına sahip biri, kabul edilen cevapta ona dokunmalıdır. Kodumda getConstants () işlevinde 'self ::' yerine 'static ::' yöntemini kullanarak ve alt numaralarda $ constCache yeniden bildirerek çözdüm.
Sp3igel

Seksi olmayabilir, ancak bir arabirim sabiti kullanmak PHP'ye gitmenin en iyi yolu olabilir.
Anthony Rutledge

27

Sabitleri olan sınıflar kullandım:

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

print Enum::NAME;

27

Bunun interfaceyerine kullanıyorum class:

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

var $today = DaysOfWeek::Sunday;

6
class Foo implements DaysOfWeek { }ve sonra Foo::Sunday... ne?
Dan Lugg

3
Soru yazarı iki şey için bir çözüm istiyor: isim alanı ve IDE'ler tarafından otomatik tamamlama. En yüksek puanlı cevabın önerdiği gibi, en kolay yol class(veya interfacesadece bir tercih meselesidir) kullanmaktır.
Andi T

4
arabirimleri sınıf uygulama bütünlüğünü zorlamak için kullanılır, bu bir arabirimin kapsamı dışındadır
user3886650 22:15

2
@ user3886650 Arabirimler Java'da sabit değerleri korumak için kullanılabilir ve kullanılmıştır. Bu nedenle, yalnızca sabit değerler elde etmek için bir sınıfı başlatmak zorunda değilsiniz ve herhangi bir IDE bunlarda kod tamamlama sunar. Ayrıca, bu arabirimi uygulayan bir sınıf oluşturursanız, tüm bu sabitleri miras alacaktır - bazen oldukça kullanışlıdır.
Alex

@ user3886650 Doğru, ancak PHP'de arabirimlerin sabitleri olabilir. Ayrıca, bu arabirim sabitleri, sınıflar veya çocukları uygulanarak geçersiz kılınamaz. Aslında, bu PHP açısından en iyi cevaptır, çünkü geçersiz kılınabilecek her şey sabit bir şekilde olması gerektiği gibi çalışmaz. Sabit, bazen değil, sabit anlamına gelmelidir (polimorfizm bazen yararlı olsa da).
Anthony Rutledge

25

Burada diğer cevaplar hakkında yorum yaptım, bu yüzden ben de tartmak düşündüm. Günün sonunda, PHP yazılan numaralandırmaları desteklemediğinden, iki yoldan birine gidebilirsiniz: yazılan numaralandırmaları kesmek veya etkili bir şekilde kesmek için son derece zor oldukları gerçeğiyle yaşamak.

Gerçekle yaşamayı tercih ediyorum ve bunun yerine constdiğer cevapların bir şekilde kullandığı yöntemi kullanmayı tercih ediyorum :

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());
    }

}

Örnek bir numaralandırma:

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;

}

Kullanarak Enumdiğer numaralandırma uzandığı bir temel sınıf gibi yardımcı yöntemleri sağlar toArray, isValidve böyle devam eder. Bana göre, yazılan numaralandırmalar ( ve örneklerini yönetme ) çok dağınık hale geliyor.


farazi

Eğer bir __getStaticsihirli yöntem ( ve tercihen de bir __equalssihirli yöntem ) mevcut olsaydı , bunların çoğu bir çeşit çokluton deseniyle hafifletilebilirdi.

( Aşağıdaki varsayımsal; o olmaz eser, bu olacak olsa belki bir gün )

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

Bu cevabın basitliğini gerçekten seviyorum. Daha sonra geri dönebileceğiniz ve bir tür saldırıya uğramış bir yaklaşım yapmış gibi görünmeden nasıl çalıştığını hızlıca anlayabileceğiniz bir şey. Utanç daha fazla oy yok.
Reactgular

23

Peki, php enum gibi basit bir java için kullanıyorum:

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

Ve buna seslenmek için:

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

Ama ben bir PHP acemi, sentaks ile mücadele böylece bu en iyi yolu olmayabilir. Sınıf Sabitleri ile denedim, Yansıma'dan sabit adı almak için Yansıma kullanarak daha temiz olabilir.


İyi cevap, diğer cevapların çoğu sınıfları kullanıyor. Yine de iç içe dersler olamaz.
Keyo

Bu, foreach ile değerler arasında yineleme yapabilme avantajına sahiptir. Ve yasadışı bir değerin yakalanma tehlikesi.
Bob Stein

2
Ancak IDE'de otomatik tamamlama yok, bu yüzden tahmin çalışmasını teşvik edecek. Sabitler otomatik tamamlamayı etkinleştirir, kulağa daha iyi gelir.
KrekkieD

19

Dört yıl sonra tekrar karşılaştım. Mevcut yaklaşımım, IDE'de kod tamamlamanın yanı sıra tür güvenliğine de izin verdiği için budur:

Temel sınıf:

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

Örnek Numaralandırma:

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

Örnek kullanım:

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

Aynı numaralandırma girişinin tüm örneklerinin aynı olduğunu unutmayın:

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

Bir switch ifadesinin içinde de kullanabilirsiniz:

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

Ayrıca ad veya değere göre bir numaralandırma girişi de oluşturabilirsiniz:

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

Ya da sadece mevcut bir numaralandırma girişinden adı (yani işlev adını) alabilirsiniz:

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

Özel bir kurucu için +1. Ben yardımcı soyut sınıf, sadece basit bir sınıf, özel yapıcı ve bazı yapmazdımconst Monday = DaysOfWeek('Monday');
Kangur

9

Bu kütüphaneyi github'da buldum ve buradaki cevaplara çok iyi bir alternatif olduğunu düşünüyorum.

SplEnum'dan esinlenen PHP Enum uygulaması

  • Aşağıdakileri yazabilirsiniz: function setAction(Action $action) {
  • Enumu yöntemlerle zenginleştirebilirsiniz (örn format. parse,…)
  • Yeni değerleri eklemek için numaralandırmayı genişletebilirsiniz ( finalönlemek için numaralandırın )
  • Olası tüm değerlerin bir listesini alabilirsiniz (aşağıya bakın)

deklarasyon

<?php
use MyCLabs\Enum\Enum;

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

kullanım

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

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

type-hint enum değerleri:

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

1
Bu doğru yanıttır ( enumşimdilik, PHP 7.x'e eklenene kadar ) tür ipucuna izin vermektedir.
Tobia

1
Bu sadece tip ipucuna izin vermekle kalmaz , aynı zamanda __toString()sihir nedeniyle, genellikle numaralandırmalarla gerçekten ne yapmak istediğinizi yapmanıza izin verir - bunları doğrudan switchveya ifdeğerlerin değerleriyle karşılaştırarak bir veya ifadesinde kullanın. Yerel enum desteği yetersiz IMO, en iyi yaklaşım.
LinusR

7

Küresel olarak benzersiz olan (yani farklı Numaralandırmalar arasındaki öğeleri karşılaştırırken bile) ve kullanımı kolay olan numaralandırmalar kullanmanız gerekiyorsa, aşağıdaki kodu kullanmaktan çekinmeyin. Yararlı bulduğum bazı yöntemler de ekledim. Kodun en üstündeki yorumlarda örnekler bulacaksınız.

<?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
Bunu çok seviyorum. Bununla birlikte, birincil şikayetlerden biri IDE'nin otomatik tamamlama için değerleri alma yeteneğidir. Bunun IDE için özel bir addon olmadan bunu yapabileceğinden emin değilim. Yapamadığından değil, sadece biraz iş gerektirecekti.
corsiKa

2
Kullanılması eval()yeni Numaralamalar Buy sen ilan edebilir bu yüzden sadece? Eek. Ben hissetmiyorum. Doğru sınıfı tanımlamaya başlamadan önce diğer sınıfların yanlış bir Enum sınıfı oluşturmasını nasıl önlersiniz? Numaralandırmalar çalışma zamanından önce bilinmiyor mu? @CorsiKa'nın da ima ettiği gibi IDE otomatik tamamlama yok. Gördüğüm tek fayda tembel kodlama.
KrekkieD

7

Java'dan enums seviyorum ve bu nedenle enums benim bu şekilde yazmak, bu Java enums gibi en benzer behawior olduğunu düşünüyorum, tabii ki, bazı java daha fazla yöntem kullanmak istiyorsanız buraya yazmanız gerekir, ya da soyut sınıf ama temel fikir aşağıdaki kod gömülü


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
İki küçük eklemeyle hemen hemen aynı şeyi yapıyorum: Statik değerlerin arkasındaki statik değerleri gizledim. Bunun bir nedeni görsel olarak tercih yani, FruitsEnum::Apple()üzerinde FruitsEnum::$Apple, ama daha önemli bir neden ayarından başkasının önlemektir $APPLEböylece tüm uygulama için enum kırma. Diğeri, ilk kez çağırdıktan sonra aramanın işlem yapılmamasını $initializedsağlayan basit bir özel statik bayraktır init()(böylece hiç kimse bununla uğraşamaz).
Martin Ender

Martin'i sevdim. .init()garip ve alıcı yaklaşımı umrumda değil.
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

PHP enum's gördüm en yaygın çözüm, genel bir enum sınıfı oluşturmak ve sonra genişletmek oldu. Sen bir göz sürebilir bu .

GÜNCELLEME: Alternatif buldum bu phpclasses.org dan.


1
Uygulama kaygan olmasına ve muhtemelen işi yapmasına rağmen, bunun dezavantajı IDE'lerin muhtemelen numaralandırmayı otomatik olarak nasıl dolduracaklarını bilmemesidir. Phpclasses.org adresinden inceleyemedim, çünkü kayıt olmamı istedi.
Henrik Paul

5

İşte php tipi güvenli numaralandırma işlemek için bir github kütüphanesi:

Bu kütüphane, sınıf oluşturma, sınıf önbellekleme işlemlerini gerçekleştirir ve numaralandırmalarla ilgili sıralama için sıralı alma veya numaralandırma kombinasyonları için ikili bir değer alma gibi çeşitli yardımcı yöntemlerle Tür Güvenli Numaralandırma tasarım desenini uygular.

Oluşturulan kod, aynı zamanda yapılandırılabilir düz eski bir php şablon dosyası kullanır, böylece kendi şablonunuzu sağlayabilirsiniz.

Phpunit ile kaplı tam testtir.

github üzerinde php-enums (çatal çekinmeyin)

Kullanım: (@ use.php veya daha fazla ayrıntı için birim testlerine bakın)

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

Çıktı:

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

Aşağıdaki yaklaşımı kullanarak işlev parametreleri, NetBeans'te otomatik tamamlama ve iyi performans için tip güvenliğine sahip olma yeteneğini verdiğim için kullandım. Çok sevmediğim tek şey [extended class name]::enumerate();, sınıfı tanımladıktan sonra aramak zorunda olmanız .

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");

Hiçbir şey enum değerlerini yeniden tanımlamanızı engellemez:DaysOfWeek::$MONDAY = 3;
KrekkieD

@BrianFisher, artık geç bir nit olduğunu biliyorum, ama [extended class name]::enumerate();tanımdan sonra çağırmayı sevmiyorsanız , neden yapıda yapmıyorsunuz?
Can O 'Spam

4

Aşağıdaki Enum sınıfı tanımım Güçlü yazılmış ve kullanımı ve tanımlanması çok doğal .

Tanım:

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

Enum'u değiştir

$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

Enum'u parametre olarak ilet (Güçlü yazılmış)

/** 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

Dize olarak Yankı Enum

echo "I have an $myFruit\n";

>> I have an APPLE

Enum'u tamsayı ile al

$myFruit = Fruit::getByValue(2);

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

>> Now I have an ORANGE

Numaralandırmaya Göre Numaralandır

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

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

>> But I definitely prefer an APPLE

Enum Sınıfı:

/**
 * @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;
    }

}

İlave

Tabii ki IDE'ler için yorum da ekleyebilirsiniz

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

Bunun çok çok eski bir konu olduğunu fark ettim ama bunun hakkında bir düşüncem vardı ve insanların ne düşündüğünü bilmek istedim.

Notlar: Bununla oynuyordum ve __call()işlevi değiştirdiysem gerçeğe daha da yaklaşabileceğinizi fark ettim enums. __call()Fonksiyon Tüm bilinmeyen işlev çağrıları yönetir. Diyelim ki üç enumsRED_LIGHT, YELLOW_LIGHT ve GREEN_LIGHT yapmak istiyorsunuz . Bunu sadece aşağıdakileri yaparak yapabilirsiniz:

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

Tanımlandıktan sonra yapmanız gereken tek şey değerleri almak için tekrar aramaktır:

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

ve 0, 1 ve 2 almalısınız. İyi eğlenceler! Bu da şimdi GitHub'da.

Güncelleme: Hem __get()ve hem de __set()fonksiyonların artık kullanılmasını sağladım. Bunlar, istemediğiniz sürece bir işlevi çağırmanıza gerek yoktur. Bunun yerine, şimdi sadece şunu söyleyebilirsiniz:

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

Değerlerin hem yaratılması hem elde edilmesi için. Değişkenler başlangıçta tanımlanmadığından __get(), dizideki girişin yapılmadığını gören işlev çağrılır (belirtilen bir değer olmadığından). Böylece girişi yapar, verilen son değeri artı bir (+1) atar, son değer değişkenini artırır ve TRUE değerini döndürür. Değeri ayarlarsanız:

$c->RED_LIGHT = 85;

Ardından __set()işlev çağrılır ve son değer yeni değere artı bir (+1) olarak ayarlanır. Şimdi sıralamalar yapmak için oldukça iyi bir yolumuz var ve bunlar anında oluşturulabilir.

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

Bu eski bir iş parçacığı olduğunu biliyorum, ancak gördüğüm geçici çözümlerin hiçbiri gerçekten numaralandırma gibi görünmüyordu, çünkü neredeyse tüm geçici çözümler el ile numaralandırma öğelerine değer atamanızı gerektiriyor veya bir dizi numaralandırma anahtarını geçirmenizi gerektiriyor işlevi. Bunun için kendi çözümümü yarattım.

Çözümümü kullanarak bir enum sınıfı oluşturmak için, bu Enum sınıfını aşağıda genişletebilir, bir grup statik değişken oluşturabilir (bunları başlatmaya gerek yoktur) ve enum sınıfınızın tanımının hemen altında yourEnumClass :: init () öğesine bir çağrı yapabilirsiniz. .

edit: Bu sadece php> = 5.3 çalışır, ancak büyük olasılıkla eski sürümlerinde çalışmak üzere değiştirilebilir

/**
 * 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

Artık SplEnum sınıfını yerel olarak oluşturmak için kullanabilirsiniz . Resmi belgelere göre.

SplEnum, PHP'de yerel olarak numaralandırma nesnelerini taklit etme ve oluşturma yeteneği verir.

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

Lütfen bunun yüklenmesi gereken bir uzantı olduğunu, ancak varsayılan olarak kullanılamadığını unutmayın. Hangi php web sitesinde açıklanan Özel Türler altında geliyor . Yukarıdaki örnek PHP sitesinden alınmıştır.


3

Son olarak, geçersiz kılınamayan sabitlerle bir PHP 7.1+ yanıtı.

/**
 * 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.
}

Ad alanlarını kullanıyorsanız, kod tamamlamanın çalışması gerekir.

Ancak bunu yaparken, sınıf ailesindeki ( protected) veya yalnızca sınıftaki ( ) sabitleri gizleme yeteneğini kaybedersiniz private. Tanım olarak, bir in her şey Interfaceolduğupublic .

PHP Kılavuzu: Arayüzler


Bu Java değil. Bu, bir üst sınıftaki sabitleri geçersiz kılmak için polimorfizm / Strateji paterninin gerekli olmadığı durumlarda işe yarar.
Anthony Rutledge

2

Bu benim "dinamik" enum benim almak olduğunu ... böylece değişkenler ile çağırabilir, ex. bir formdan.

Bu kod bloğunun altındaki güncellenmiş sürüme bakın ...

$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);
    }
}

GÜNCELLEME: Bunu yapmanın daha iyi bir yolu ...

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;

}

İle ara

EnumCategory::${$category};

5
Bu sorunla ilgili sorun; EnumCategory::$sport = 9;. Spor müzesine hoş geldiniz. const olduğunu bunu yapmanın daha iyi bir yolu.
Dan Lugg

2

Kabul edilen cevap, gidilecek yol ve aslında basitlik için yaptığım şey. Numaralandırmanın çoğu avantajı sunulmaktadır (okunabilir, hızlı, vb.). Ancak bir kavram eksik: tip güvenliği. Çoğu dilde, numaralandırmalar izin verilen değerleri kısıtlamak için de kullanılır. Aşağıda, özel yapıcılar, statik örnekleme yöntemleri ve tür denetimi kullanılarak tür güvenliğinin nasıl sağlanabileceğinin bir örneği verilmiştir:

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());

Daha da ileri gidebiliriz: DaysOfWeek sınıfında sabitleri kullanmak yanlış kullanıma neden olabilir: örneğin biri yanlışlıkla bu şekilde kullanabilir:

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

bu yanlış (tamsayı sabiti çağırır). Bunu sabitler yerine özel statik değişkenler kullanarak önleyebiliriz:

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

}

Tabii ki, tamsayı sabitlere erişmek mümkün değildir (aslında amaç budur). İntVal yöntemi, bir DaysOfWeek nesnesini tamsayı gösterimine dönüştürmeye izin verir.

Numaralandırmaların yaygın olarak kullanılması durumunda hafızayı korumak için örnekleme yöntemlerinde bir önbellek mekanizması uygulayarak daha da ileri gidebileceğimizi unutmayın ...

Umarım bu yardımcı olur


2

Burada bazı iyi çözümler!

İşte benim versiyonum.

  • Güçlü yazılmış
  • IDE otomatik tamamlama ile çalışır
  • Numaralandırmalar, bir tamsayı, bir ikili değer, kısa bir dize veya temelde istediğiniz herhangi bir şey olabileceği bir kod ve açıklama ile tanımlanır. Desen, diğer özellikleri desteklemek için kolayca genişletilebilir.
  • Değer (==) ve referans (===) karşılaştırmalarını destekler ve anahtar ifadelerinde çalışır.

Ana dezavantajı, açıklamaları ve PHP statik üye bildirim zamanında nesneleri inşa edememesi nedeniyle numaralandırma üyeleri ayrı ayrı beyan ve örnek olması gerektiğini düşünüyorum. Sanırım bu bir yol bunun yerine ayrıştırılmış doktor yorumları ile yansıma kullanmak olabilir.

Soyut enum şöyle görünür:

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

İşte somut bir numaralandırma örneği:

<?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();

Hangi böyle kullanılabilir:

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

Ve bu çıktıyı üretir:

1: İlk değerim

dizi (3) {
[1] =>
nesne (EMyEnum) # 1 (2) {
["kod": "AbstractEnum": private] =>
int (1)
["description": "AbstractEnum": private] =>
string (14) "İlk değerim "
}
[2] =>
nesne (EMyEnum) # 2 (2) {
["kod": "AbstractEnum": private] =>
int (2)
["description": "AbstractEnum" : private] =>
string (15) "İkinci değerim "
}
[3] =>
nesne (EMyEnum) # 3 (2) {
["code": "AbstractEnum": private] =>
int (3)
["description": "AbstractEnum": özel] =>
string (14) "Üçüncü değerim"
}
}

İkinci değerim


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 ) );

Yansımayı kullanma. Kodunuz hakkında akıl yürütmeyi ve bir şeyin nerede kullanıldığını takip etmeyi son derece zorlaştırır ve statik analiz araçlarını (örneğin IDE'nize yerleşik olanları) kırma eğilimindedir.


2

Buradaki diğer cevaplardan bazılarında eksik olan yönlerden biri, tür ipucu ile numaralandırmaları kullanmanın bir yoludur.

Numaralandırmanızı soyut bir sınıfta sabitler kümesi olarak tanımlarsanız, ör.

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

o zaman bir fonksiyon parametresinde bunu ima yazamaz - bu örneklenebilir değil çünkü, biri için değil, aynı zamanda tipi nedeniyle ShirtSize::SMALLolduğunu intdeğil ShirtSize.

Bu yüzden PHP'deki yerel numaralandırmalar gelebileceğimiz her şeyden çok daha iyi olurdu. Bununla birlikte, enumun değerini temsil eden özel bir özelliği koruyarak ve sonra bu özelliğin başlatılmasını önceden tanımlanmış sabitlerimizle sınırlandırarak bir enum'a yaklaşabiliriz. Numaralandırmanın keyfi olarak başlatılmasını önlemek için (bir beyaz listenin tür denetlenmesi yükü olmadan), yapıcıyı özel yapıyoruz.

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

O zaman böyle kullanabiliriz ShirtSize:

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";

Bu şekilde, kullanıcının bakış açısından en büyük fark (), sabitin adına a takmanız gerektiğidir .

Bir dezavantajı ===(nesne eşitliğini karşılaştıran) ==true döndürdüğünde false döndürecektir. Bu nedenle, bir sağlamak için en iyisi equalskullanıcıların kullanmak için hatırlamak zorunda kalmamak için bu, yöntem ==ve ===iki enum değerleri karşılaştırmak için.

DÜZENLEME: Mevcut yanıtlardan birkaçı çok benzer, özellikle: https://stackoverflow.com/a/25526473/2407870 .


2

@Brian Cline'ın cevabına adım atarak 5 sentimi verebileceğimi düşündüm

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

nedense bu işlevler diyemiyorum. Bana bu tür işlevlerin açıklanmadığını söylüyor. Neyi yanlış yapıyorum? [temel Enum sınıfı başka bir dosyada yer alıyorum ve kullanıyorum include('enums.php');]. Herhangi bir nedenle çocuk sınıfları için Enum'da bildirilen işlevleri görmüyor ...
Andrew

Ayrıca ... nasıl dizeden ayarlamak için? sth like$currentSeason.set("Spring");
Andrew

1

PHP ile bir numaralandırma oluşturma girişimim ... enum değerleri olarak nesneleri desteklemediğinden, ancak yine de biraz yararlı olduğu için son derece sınırlı ...

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();
    }
}

birçok yönden sınırlıdır ve mevcut cevaplar çok daha fazlasını sunar. Bunun gerçekten yararlı bir şey eklemediğini söyleyebilirim.
hakre

1

Dün bu sınıfı bloguma yazdım . Bence php betiklerinde kullanmak kolay olabilir:

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

Kullanımı:

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

2
Ama iyi bir sınıf ve işlev isimleri yerli. Ayrıca translate.google.ru da yardım edebilir.
Arturgspb

2
Chrome'ları kullanın ve çevirin, eğer programcıysanız, kodu okursunuz!
markus

8
Genel olarak, kodu 'n' ay / yıl içinde bulunabilecek veya olmayabilecek bir harici kaynağa bağlamak yerine cevaba dahil etmek her zaman daha iyidir.
John Parker

Sınıfım çok büyük ve bu yazıyı okumanın sakıncalı olacağını düşünüyorum.
Arturgspb

Bence burada iki kötü şey var: Rusça (her programcı ingilizce bilmeli ve yorumlarda bile kullanmalıdır) ve buraya dahil değildir. Devasa kodu nasıl ekleyeceğiniz konusunda yardıma bakın.
Mart'ta
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.