Edit report at https://bugs.php.net/bug.php?id=48277&edit=1

 ID:                 48277
 Comment by:         knight at kopernet dot org
 Reported by:        nairbv at yahoo dot com
 Summary:            need a way to do type safe enumerations in php
 Status:             Open
 Type:               Feature/Change Request
 Package:            Feature/Change Request
 PHP Version:        6CVS-2009-05-14 (CVS)
 Block user comment: N
 Private report:     N

 New Comment:

I hope one day we get rid of the final keyword altogether and instead of a 
fatal error it generates we just get a decent warning in the log file.
I'd be far more happy and feel safer as well if the PHP team considered using 
uninitialized variable a bigger issue.
The same goes for type hints which just make the code so much more rigid and 
make it so difficult writing unittest for example. Why must it throw a fatal 
instead of a warning?


Previous Comments:
------------------------------------------------------------------------
[2009-05-14 08:38:04] nairbv at yahoo dot com

Description:
------------
**This is a feature request, not a bug

I can find no reasonable way of implementing any kind of useful typesafe 
enumeration pattern in php without an additional language feature.  There are a 
number of potential language features that could fix this.  Here are a couple 
of examples.

1) a "final" keyword for static class members, and permitting static 
initialisation at class load time.  Final is *not* the same thing as "const."  
"final" + load-time initialisers would allow code like this:

final class color {
    private $name;
    public static final $RED = new boolean('Red');
    public static final $ORANGE = new boolean('Orange');
    //.....
    function __construct($name){ $this->name=$name; }
    function __toString() { return $this->name; }
}

without static, you can't initialise them in the class.  Without final, any 
user of your class can color::RED = color::ORANGE (maybe accidentally in an if 
statement) and you're class is hosed.  With const, they can only be primitives, 
which can't have any functionality or attributes.  Finals would be initialised 
at run time (sometimes even in constructors etc, as long as they are only 
initialised once).

Don't confuse what I said about static initialisers with "late static binding," 
an already planned feature un-related to this request.

2) or, including an actual enum class would be nice.  see:
http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html for an example.

3) ideally we'd have both.  Having an enum class is obviously better than my 
first suggestion for the specific problem of implementing enums, but the 
features in my first suggestion also have other applications.

I'm seeing a lot of code that in various ways attempts to work around this 
lack.  None of them are elegant, in that they all involve repetitive, hard to 
read, or unsafe code.

one example I came across recently looked like this:
final class foo {
    static $foo;
    static $bar;

    function __construct()
    {
        $foo = new someotherclass('attribute1','attribute2');
        $bar = new someotherclass('attribute3','attribute4');
    }
}
new foo();

there was a comment before "new foo();" in this code (written by someone else) 
that said:

"need to instantiate class to fill static members. I don't like this setup, but 
haven't found a better way yet to have const members of class or interface be 
instantiated objects rather than constant expressions."

It happens frequently enough.  In this code that I found, an accidental 
assignment in an if statement breaks other calling code due to lack of final.  
Lack of load-time static initialisation means that class members have to be 
instantiated by a call outside the class definition, and that every member (the 
real class has about 100 members) has to be defined twice.

I've also seen code like:

final class my_things {
    private $name;
    private static $all_things = array();
    function __construct($name,$otherstuff) {
        $this->name=$name;
        ....
        self::$all_things[$name] = $this;
    }
    static function get_by_name($name) { 
        return self::$all_things[$name]; 
    }
}

new my_things('thing1',...);
new my_things('thing2',...);
....

which, is also far less than ideal... and doesn't maintain any usable reference 
to the actual enumeration.  Each one must be looked up by it's reference 
string, often defined elsewhere as a series of consts.  It can also be added to 
since the constructor must be public.

The closest you can come to getting a real enum in php is to use public static 
final functions to get the enumerated values.  This requires a lot of plumbing 
code, i.e., a factory method that caches values so new ones are not constructed 
on every call (because we want to boolean::TRUE() === boolean::TRUE() not just 
==, etc), and an entire function definition in which each enumerated value is 
instantiated/returned.

The late static binding feature being added in 5.3 might enable someone to 
write an enum superclass (function based) getting around *some* of this 
plumbing code, but using functions as enumerations would still be an ugly hack.

There are so many places where this is useful.  Say I want to add a list of log 
levels to a logging class.  I want each log level to be a numeric value that 
can be compared, and have a string representation that can be printed.  It 
can't be done in any safe, non-repetitive, object oriented, clean way.



Reproduce code:
---------------
n/a

Expected result:
----------------
n/a

Actual result:
--------------
n/a


------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=48277&edit=1

Reply via email to