Validating data in PHP objects using magic methods
I've been working with PHP lately and when deserializing a model I wanted to have a generic way of adding validations for its properties, so I thought whether there was a way for hooking into an object's properties while getting/setting them, much like the Proxy object in javascript.
I found that magic methods in PHP would do the trick. Magic methods overwrite the object's default functionality when the event that triggers them happens. The most commonly used is the __construct()
method, the constructor for the object.
Using the __get
and __set
magic methods, we can hook into the property when getting & setting it and run our custom logic. Hence, creating a bunch of validators to verify we're not assigning them any forbidden values:
class User {
public $allowedProperties = [ 'firstName', 'email' ];
private $firstName;
private $email;
public function __set($propertyName, $value) {
if (!in_array($propertyName, $this->allowedProperties)) {
throw new Exception('Property: ' . $propertyName . ' not supported');
}
$validator = $propertyName . 'Validator';
$isPropertyValueValid = $this->$validator($value);
if (!$isPropertyValueValid) {
throw new Exception('Value: ' . $value . ' for: ' . $propertyName);
}
$this->$propertyName = $value;
}
public function __get($propertyName) {
if (!in_array($propertyName, $this->allowedProperties)) {
throw new Exception('Property: ' . $propertyName . ' not supported');
}
return $this->$propertyName;
}
private function firstNameValidator($value) {
return is_string($value) && strlen($value) < 25;
}
private function emailValidator($value) {
return filter_var($value, FILTER_VALIDATE_EMAIL);
}
}
$user = new User();
$user->firstName = 'Ahhhh I am longer than 25 characters nooooooo'; // throw Exception
$user->email = 'esteban@gmail.com';
It is important to point out that by using this strategy we'll lose any static analysis we have, so it's a choice to make.
Have fun!