Explicit PHP6?
Some days ago I read Fabien Potencier’s post ‘What for PHP 6’ pointing me to some features that might be implemented in PHP6. Two of those would have been nice in a project I’m currently working on where I’ve been experimenting with ‘domain objects’ having ‘scalar’ or ‘value’ objects as properties (more on that later). The first is scalar type hinting and hinted return values. The other is a __cast() method that replaces (or complements __toString()). Now that sounds quite java-ish and one of PHP merits is it’s flexibility but having the option to be more strict in my opinion is a good thing: If I feed my application with garbage I don’t blame it for being equally blunt.
Consider a User object that has the properties userid, email and admin.
class User
{
protected $userId;
protected $email;
protected $admin;
public function setUserId(UserId $userId) {}
public function setEmail(Email $email) {}
// this should only accept a boolean
public function setAdmin($isAdmin)
{
if (!is_bool($isAdmin)) {
throw new ValueTypeException(
'Wrong parameter for ' . __METHOD__
);
}
$this->admin = $isAdmin;
}
}
Here being able to enforce the boolean parameter would be nice and more consequent with the other methods.
The Email value object has it’s own validation and could look like this:
class Email
{
private $value;
public __construct($value)
{
if (!preg_match('/^.+\@.+\..+$/',$value) {
throw new ScalarValueException(
'Invalid value for type Email'
);
}
$this->value = $value;
}
public function __toString()
{
return $this->value;
}
}
Now let’s look at how a PHP6 UserId object might look like:
class UserId
{
private $value;
public __construct($value)
{
$isValid = true;
if (!is_int($value) ||
!$this->exists($value) ||
$value <=0
) {
throw new ScalarValueException(
'Invalid value for type UserId'
);
}
$this->value = (int) $value;
}
// Warning: uses PHP6 proposed features
public function __cast($type)
{
if ($type == 'int') {
// return integer value
return $this->value;
}
if ($type == 'boolean') {
// return true as UserId can only
// exist with a valid value
return true;
}
throw new SkalarInvalidCastException(
'Object of type UserId cannot be cast to '.$type
);
}
private function exists($value)
{
// method that checks if a user with given id exists
}
}
As can be seen the __cast() method assumably (it’s just a proposed feature) accepts a $type parameter. That raises the question if it wouldn’t be better to add __toInteger(), __toFloat() and __toBoolean() methods instead. That seems more consequent with the __toString() method that’s allready widely used.
The C#-style properties with getters and setters might be nice too, although imho it doesn’t really add much to the allready existing __set() and __get() methods. I would prefer to see ‘strongly typed’ properties instead:
class User
{
// PHP6 wishlist: strong typed properties
protected UserId $userId;
protected Email $email;
protected boolean $admin;
// etc...
}
I’m really looking forward to these kind of additions, especially if such type hinting is kept optional. Then the flexibility of PHP is preserved but it allows for a more robust approach in large projects.
Be explicit. Type strong.