Pull to refresh

Comments 54

Неплохое решение, отшлифовать в реальном приложении до блеска и весьма полезная штука будет.
без подсветки синтаксиса — не оч удобно читать =\
идея понравилась
З.Ы. А вот когда выйдет релиз PHP5.3, то можно будет добавить к класс Enum метод:
public static method asArray() {}



А что мешает сделать это сейчас?

$ColorReflection = new ReflectionClass("Enum_Colors");
printf("<pre>%s
«, print_r($ColorReflection->getConstants(), TRUE));

Array
(
[RED] => F00
[GREEN] => 0F0
[BLUE] => 00F
)
то что такой метод придется писать в каждом классе, а вот с LSB он будет только в родительском
а если просто реализовать класс констант без проверки? в чем практический плюс Вашего метода? в создании экземпляра класса? и зачем сравнивать коонстанты класса с константами экземпляря этого же класса?
беру свои слова назад, но создание экземпляра явный минус подхода :)
подобные экземпляры не будут ощутимыми для приложения :) поверьте. ну или проверьте :)
В родительском

$ColorReflection = new ReflectionClass(get_called_class());
ну в этом примере тоже есть недостаток, надо создавать объект каждый раз для получения результата
а это смотря из какого контекста вы будете работать с перечислением :)
Если необходимо использовать преимущество type hintэинга, то создаете экземпляр
А если надо просто работать со значением — статический вызов константы никто не отменял
как бы вот проще:
final class enum
{
private $something;
public function __construct($val)
{
$this->something = $val;
}
public function eget($index='')
{
if($index=='') return $this->something;
if(! isset($this->something[$index])) return NULL;
return $this->something[$index];
}
}


<?
$array = array(«red»=>«#FF0000», «green»=>«#00FF00», «blue»=>«#0000FF»);
$enum = new enum($array);

echo $enum->eget(«red»);

?>


где-то так ;)
ну первое замечание — что бы использовать значение перечисления в Вашем варианте надо сначала создать объект (new), а затем вызвать метод. Тоесть отпадает вариант простого использования как аргумента:

useMyFunction( new Color_Enum( 'RED' ) );
&lt!-- у Вас аткое не прокатит,

а во-вторых — Ваш вариант не застрахован от того, что где-то в середине кода перечисолление будет переопределено, что противоречит первоначальной идеи перечислений (что бы поведение было как у констант)
Эээммм, мне тут подумалось, что возможно enum-ы в пхп и не нужны и вполне достаточно констант? Ведь не зря же их не сделали.
Вполне вероятно, что вы пытаетесь «натягивать» функционал и методологию другого языка на пхп, в котором, вероятно, есть другие решения.
Например, я не вполне понимаю, чем вам не нравятся define()? Группировка, как по мне, — это чисто эстетический аргумент, например
enum { fOne, fTwo, fThree };
тоже только эстетически группируется. Проверка типов — это вообще интересно, так как в пхп нет типов в терминах «других» языков, так зачем лепить эти типы, если они не нужны?
В конце-концов не ясно, в чем разница между f(new Enum_Colors( 'GREEN' )) и f('00ff00'). Имхо, ясно одно, что вы на пхп пытаетесь реализовать яву/с++, что, вобщем то, не нужно и вредно ;) А это уже огрехи проектирования либо мышления в рамках языка.
я люблю type hint'ы, так как с ними проще работать в команде

и именно в этом и отличается f(new Enum_Colors( 'GREEN' )) и f('00ff00'), что я могу указать какой именно параметр будет ожидать функция

з.ы. я, кстати, совершенно не настаиваю на использовании этого довеска, но если кому-то нехватало энумов, то вот решение…
Дык я потому и спрашиваю, что бы разъяснить для себя некоторые вещи :)
Видел я похожие решения для перла тоже, в связи с этим у меня возникают вопросы касательно эффективности этих методов. То есть, что эффективнее описать функцию в комментариях к ней либо применять подобные решения? Что эффективнее в контексте исполнения кода? Я так полагаю, что константа работает быстрее, не замедлят ли подобные решения весь код в целом? Я понимаю, что гигагерцы, кластеры и прочее, но как-то всегда стараюсь максимально оптимизировать.
То есть, как бы я хочу разъяснить, не приведет ли повышение эффективности в читабельности к падению эффективности в работе кода?
мне кажется что НЕ использовать это решение (если оно Вам таки надо) ради оптимизации производительности, это все равно что использовать echo вместо print (или наоборот?) и одинарные кавычки вместо двойных :)
я готов жертвовать в разумных пределах производительностью в счет удобочитаемости и понимания кода
Дефайны не положишь в нэймспэйсы, а неймспейсы — важный аспект любого ОО-языка. Дефайны из мира С и ПХП 3/4.
я вас умоляю, пхп — это ОО-язык? куда катится мир :(
Может не будет столь поспешны в рамках пхп, а то ява и C# просто удавятся от обиды :-)
да — PHP ОО язык. Это уже многократно обосновывалось даже тут — на хабре. И попрошу в этой ветке холивары не разводить. Спасибо
займись java(я серьезно), многое станет на свои места. Класс ради класса — это перебор.
начните писать «с использованием языка», а не «на языке»
:) наивно, эти строчки должен был я сказать, меня упрекнуть по крайней мере бестолково.
Ява далеко не самый лучший оо-язык. Займись лучше smalltalk.
не самый лучший, но самый ооп-истый :)
ПХП — объектно-ориентированый язык, правда с повсеместными костылями. Ява и До диез — тоже не эталон, это скорее мейнстрим.
кстати вот в РНР5.3 перечисления уже и появились :)
Про это?
www.php.net/manual/en/class.splenum.php
В частности: «SplEnum gives the ability to emulate and create „Enum“ objects natively in PHP. „

Насколько я понимаю это аналог
class MyEnumType { const A = 0; const B = 1; const C = 3; }
не совсем, но это действительно еще не тот энум, которого я жду :)
Спасибо! Мне понравился ваш вариант.
А ещё можно добавить, что подобное решение известно под названием паттерна Type safe enum.
я своим юниорам по рукам буду бить за такие велосипеды, это усугубление ооп в очень серьезной форме.
class Enum{
const RED = 'F00';
const GREEN = '0F0';
const BLUE = '00F';
} -явная группировка, получается что патерн нужен только для тайпхинтинга :), если это важно — то да.
обсолютно не нужен $class_name = get_class( $this ); так как при try->catche он передается одним из параметров, а иначе вы эту ошибку не словите.
за strtoupper, имхо, надо убивать, т.к. КОНСТАНТЫ И ПЕРЕМЕННЫЕ РЕГИСТРОЗАВИСИМЫ, вы же пишите аналог!

P.S. new Enum_Colors( $param) vs Enum_Colors::{$param}
Что Вы хотели сказать в «P.S.»?

strtoupper тут необходим был идеологически. Класс этот опенсурс и распространяется as is :)
не могу понять за что камент получил столько минусов… я всего-лишь пытался выяснить ЧТО пытался донести автор в пост-скриптуме…
обсолютно не нужен $class_name = get_class( $this );

Уверены?
извините что не в тему, подскажите кто нибудь как узнать колличество потраченной памяти буфера php, или оставшейся
Да, типа ENUM в PHP очень не хватает.

На практике можно использовать например такое решение:
1) Группировка констант в один класс
2) Switch-блок в принимающих методах (он и без того очень часто используется в методах подобного типа) с исключением в блоке default (неизвестный тип)

Если же хочется полноценного контроля типа, то первое, что приходит на ум (но все равно все это костыли):


<?php

abstract class Color 
{
   protected $value;
   public function getValue()
   { 
       return $this->value;
   }
}

final class Color_Red extends Color
{
    protected $value = 'f00';
}

.....
....function setColor(Color $color)
Там же все совсем другое?
лучше тут __toString использовать )
но в этом варианте обращаться напрямую нельзя
тем что прежде чем сделать $color->getValue() вам надо инстанциировать объект. Если бы Вы прочли ветку по ссылке что я дал — Вы бы поняли…
не очень понятно…

function setColor(Color $color)
{
$colorVal = $color->getValue();
}

… setColor(new Color_Red())

что здесь не так?
Вы забыли упомянуть, что для использования значения такой константы его нужно принудительно приводить к (string) в нестроковых контекстах.
зачем в нестроковых контекстах приводить к строке? может наоборот? если да — тогда за это отвечает метод __toString
Для получения значения. Как из вашего енум-контейнера получить конкретное текущее значение? только через __toString, что равнозначно приведению к строке. Вот пример, в данном случае имеем числовой контекст (потому что значения констант — не строки):
class Enum_Colors extends Enum {
    const RED = 0xFF0000;
    const GREEN = 0x00FF00;
    const BLUE = 0x0000FF;
}

function something(Enum_Colors $color)
{
    switch ((string)$color) {
        case Enum_Colors::RED:
            echo 'red';
        break;
        case Enum_Colors::BLUE:
            echo 'blue';
        break;
        case Enum_Colors::GREEN:
            echo 'green';
        break;
        default:
            echo 'unknown color';
        break;
    }
}
something(new Enum_Colors('RED'));


Без принудительного приведения в switch() получаем кучу ругани и 'unknown color'. С принудительным приведением в switch и __toString (это еще один момент, php запрещает возвращать из __toString не-строки) — ожидаемый результат.
Как по мне высосано из пальца, если можно быть проще, то надо быть проще. ООП ради ООП.
Это все конечно красиво, но в сложном приложении выльется в множество объектов, которых могло и не быть. Всетаки для PHP, пожалуй, больше подходит старый добрый вариант с интовыми константами (в т.ч. класса).
Беда «волшебных» методов и динамических свойств/констант в том, что нет еще ни одной IDE, которая могла бы их понимать и помогать подстановками. Часто из-за досадной очепятки приходится тратить массу времени на поиск неуловимого глюка. Но идея хорошая.
пересматривал старые статьи по пхп. Эта в избравнное — очень хорошее решение с типизацией.
Прошло время, но я всё же напишу. Проблема выше перечисленного способа в том, что не будет работает автодополнение. Поэтому предлагаю некоторое изменение.

abstract class Enum {

    static public function __callStatic($name, $arguments){
        return new static(constant(get_called_class() . '::' . $name)); // не нужно проверять, php сам кинет ошибку.
        }

    private $current_val;

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

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

Таким образом можно будет написать Enum_Colors::, выбрать константу и дописать скобочки Enum_Colors::RED();
Sign up to leave a comment.

Articles