dagfinn | 11 May, 2008 00:04
I'm currently working about equally in PHP and Java. I can't say I've fallen in love with Java. But Java does have a feature or two that would be useful in PHP. One of them is the Enum (enumeration, that is), which is traditional in some languages and DBMSes (including MySQL) and was introduced in Java 1.5 (or is that 5.0? I'm sure they do that just to expose people like me as Java amateurs).
Enumerations are useful when a variable can have one of a given number of values. Actually useful examples I've encountered in web programming are states or stages in a process and user roles. Another kind of example is one I used in PHP In Action: an authorization system with three fixed roles or categories of user: regular, webmaster and administrator.
If we represent the roles as text strings, we risk getting our tests wrong:if ($role == 'amdinistrator')...
The only problem is that the word “administrator” is misspelled, so the test won't work.
This can be solve by representing the values with named constanst instead. Using class constants in PHP 5:class Role const REGULAR = 1; const WEBMASTER = 2; const ADMINISTRATOR = 3; ...
Now we can do this instead:
We won't get away with any misspellings here; using an undefined class constant is a fatal error. Compared to global constants, this may be easier to figure out, not least because we know where the constant is defined (inside the Role class) just by looking at it.
This is called the int Enum pattern in the official description of Java Enums. The documentation also lists some problems with this, starting with type safety, which we're not that concerned with in PHP anyway. A more relevant problem is the fact that when you print the value, you just get the number.
But I don't see why you shouldn't use strings for the values:class Role const REGULAR = 'REGULAR'; const WEBMASTER = 'WEBMASTER'; const ADMINISTRATOR = 'ADMINISTRATOR'; ...
One PHP-specific problem I didn't mention in the book is the problem that happens with long class names. Since we still don't officially have namespaces in PHP, we will easily end up with nauseatingly long constant names, like this:
It's quite depressing to have to do that a lot. I've tried putting constants in their own class with a shorter name, but I didn't like it much. One thing I tried recently was creating instance methods to return the constant value:
class MyProject_Authorization_RBAC_Role... public function REGULAR { return self::REGULAR } public function WEBMASTER { return self::WEBMASTER } public function ADMINISTRATOR { return self::ADMINISTRATOR }
Now we can create an instance with a short name and get the values from that:
$roles = new MyProject_Authorization_RBAC_Role; if ($role == $roles->ADMINISTRATOR())...
All of this just to get shorter names? I little desperate perhaps. So yes, I would like Enums in PHP.
dagfinn | 02 May, 2008 23:05
Everybody who writes object-oriented code knows about constructors. You need them so the program knows how to instantiate objects, right? And you especially need them when a lot of things have to be done while instantiating an object. And personally, I've never considered visibility restrictions important enough to be a major argument against those languages that have lacked them (PHP 4). So why would I be skeptical of public constructors?
I got the idea after reading Joshua Kerievsky's book Refactoring to Patterns. One of his refactorings is called Replace Constructors with Creation Methods. In Java, unlike PHP, you can have multiple constructors that are distinguished only by the number and type of arguments. That may be practical sometimes, but as Kerievsky's example shows, it be more readable to have creation methods with different names instead. Which is what you have to anyway in PHP.
But why not take this one step further and do it even when there is only one constructor? For example, here's an ultra-basic Redirect class:
class Redirect { private $url; public function __construct($url) { $this->url = $url; } public function execute() { header("Location: ".$this->url); exit; } }
This may seem simplistic, but it is the kind of class I might actually use at an early stage in the development of a web application. Anyway, we can apply what is essentially the same process as Kerievsky's by adding a creation method whose name is somewhat more telling than __construct().
class Redirect { private $url; public function __construct($url) { $this->url = $url; } public static function withUrl($url) { return new self($url); } public function execute() { header("Location: ".$this->url); exit; } }
Now all that remains is to make the constructor private.
private function __construct($url) { $this->url = $url; }
Is this an improvement? The additional code might be considered unnecessary complexity, or in a word: clutter. On the other hand, our client code might seem more readable when it looks like this:
$redirect = Redirect::withUrl("http://www.example.com/index.php"); $redirect->execute();
Instead of:
$redirect = new Redirect("http://www.example.com/index.php"); $redirect->execute();
You could object that it's fairly obvious anyway in this example that we're inputting a URL. But if the URL string is supplied as a variable or method call instead of a plain string, it would be less obvious.
No doubt there are many cases in which a plain constructor is the best choice, but I think this is worth considering.
| « | May 2008 | » | ||||
|---|---|---|---|---|---|---|
| Su | Mo | Tu | We | Th | Fr | Sa |
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |