12

I have one PHP5 object passing messages to another, and would like to attach a type to each message. For example, MSG_HOT, MSG_WARM, and MSG_COLD. If PHP5 had an enum type, I would probably use that to define the message types, but (unless I'm mistaken) there is no such animal. I've looked at a few options:

Strings ('MSG_HOT', 'MSG_WARM', and 'MSG_COLD') are bad because I would inevitably type something like 'MSG_WRAM' and things would break. Numbers suffer the same problem and are also less clear.

Defines work:

define('MSG_HOT', 1);
define('MSG_WARM', 2);
define('MSG_COLD', 3);

but pollute the global namespace, and thus would require more verbose names to ensure uniqueness. I'd prefer not to have my code littered with things like APPLICATIONNAME_MESSAGES_TYPE_HOT.

Finally, I could use class names to distinguish types, like so:

class MessageHot extends Message {}
class MessageWarm extends Message {}
class MessageCold extends Message {}
class Message
{
    public function Type()
    {
        return get_class($this);
    }
    public function Data()
    {
        return $this->data;
    }
    public function __construct($data)
    {
        $this->data = $data;
    }
    private $data;
}

This is good, I think, but is also a lot of work for what seems like it ought to be a simple concept.

Am I missing a better alternative?

Charles
  • 50,943
  • 13
  • 104
  • 142
Brian
  • 707
  • 8
  • 12

5 Answers5

17

A very common convention is to use class constants in PHP.

e.g.

class Message
{
    const HOT  = 0;
    const WARM = 1;
    const COLD = 2;
}
hobodave
  • 28,925
  • 4
  • 72
  • 77
  • 7
    You would use this like this: `Message::HOT`. I also believe that `Message` should be declared as `abstract`. – philfreo Dec 26 '09 at 02:55
  • Unless of course, the Message class is used for more things than just keeping constants, like `Message::Send("bla bla", Message::HOT);` – santiago arizti Jul 20 '17 at 21:30
5

I also use a class with consts for this. I add the following

  • make the class abstract, to make sure no one tries to instantiate it
  • add a static array that maps the consts to strings for printing friendly messages
  • implement a static __toString() method to do the previous

    abstract class Message {
        const HOT = 0;
        const WARM = 1;
        const COLD = 2;
    
        public static $enums= array(
            self::HOT => "hot",
            self::WARM => "warm",
            self::COLD => "cold"
        );
    
        public static __toString($enum) {
            return self::$enums[$enum];
        }
    }
    

I can also use the Message::$enums to test variables:

if (!array_key_exists($is_it_valid, Message::$enums)
grantwparks
  • 1,124
  • 9
  • 13
2

You could use class constants:

class Message
{
    const hot = 0;
    const warm = 1;
    const cold = 2;
}

foo(Message::hot);
foo(Message::warm);
foo(Message::cold);
pim
  • 12,019
  • 6
  • 66
  • 69
Greg
  • 316,276
  • 54
  • 369
  • 333
  • 1
    Heh, I swear this wasn't on the page when I answered. Greg, most PHP (PEAR,Zend, etc.) coding standards require the use of ALL CAPS for constant names. It certainly helps with code recognition. – hobodave Jul 26 '09 at 20:47
  • A convention like that is very important when you're creating your constants with define (though I find all-caps butt-ugly, so I prefer a 'k' prefix, as in kConstantName), but it's really not necessary for class constants. If you see SomeClass::foo (or self::foo or static::foo), what else can foo be besides a constant? And short of something really funky like reflection, you're only ever going to see class constants referenced like that. – mr. w Jul 27 '12 at 23:37
0

You might want to look at the two first answers to this question on stackoverflow mentionning both

Community
  • 1
  • 1
Iam Zesh
  • 1,797
  • 2
  • 20
  • 42
0

Make abstract class Enumerator:

abstract class Enumerator {
  static function enumerate() {
    return (new ReflectionClass(get_called_class()))->getConstants();
  }
  static function exists($enum) {
    return in_array($enum, self::enumerate());
  }
}

Declare your enumerations:

abstract class Message extends Enumerator {
  const HOT  = 0;
  const WARM = 1;
  const COLD = 2;
}

Use:

var_dump(Message::HOT);
var_dump(Message::WARM);
var_dump(Message::COLD);

var_dump(Message::exists(0));
var_dump(Message::exists(6));

var_dump(Message::enumerate());

Output:

int(0)
int(1)
int(2)

bool(true)
bool(false)

array(3) {
  ["HOT"]  => int(0)
  ["WARM"] => int(1)
  ["COLD"] => int(2)
}
NoSkill
  • 718
  • 5
  • 15