The current codebase of my employer has a nightmarish use of interfaces. Of the some 200 classes in the system, each and every one has a matching interface. Not one of those interfaces is reused.
I haven’t coded interfaces much. I’ve begun to make heavy use of the ones in PHP, but this isn’t exactly the same thing in my opinion because native PHP interfaces often modify the behavior of the underlying scripting engine. ArrayAccess and Iterator are two powerful and extremely useful examples.
Recently I’ve begun work on an interface when it became clear that I needed two rather disparate classes to do certain things exactly the same way. Specifically the table and the field class. The reason is that a table can be a field.
I want the code to handle this most common case of relationships between two tables - parent to child; one to many - pretty transparently.
Now unlike Doctrine or Hibernate I don’t want to build a new class every time I add a table to the database, or run a script to update that class when the field map changes.
I’m still working on both classes and the interface is being written for two reasons - to enforce that their shared concerns are handled the same way as far as the outside world is concerned. Also I want to use instanceof to detect the interface on occassion.
I’m further along with the base field class than the table at the moment. The field class is a caster and validator. It knows the minimum, maximum, and default values of the field, and whether the field value is allowed to be null, is required, is unique within the table, or unique among siblings. Extending classes will add other validations. All validations are written as closures and stored in a checks array. The class is to build this array of closures at construct time. Many of these closures are almost embarrassingly simple stuff like this snippet which defines the null check.
if (!$this->allowNull) {
$this->checks['null'] = function($val) {
return !is_null($val)
};
}
The row class actually does the validation. It extends ArrayObject and performs validation when offsetSet is called.
public function offsetSet($offset, $value) {
if ($this->valid($offset, $value)) {
parent::offsetSet($offset, $value);
} else {
throw new ValidationException();
}
}
protected function valid ($offset, $value ) {
$this->errors = array();
foreach ($this->fields[$offset]->checks as $test => $valid) {
if ($valid($value)) {
continue;
} else {
$this->errors[$offset][$test] = $value;
}
}
return count($this->errors) == 0;
}
Note the above is simplified a little but not much. The purpose to the closures approach here is that the row class that is doing the validation doesn’t need to know the details of validation for its fields.
And the thought here is that it also doesn’t need to know that the “field” is a table either
This is still heavily in flux, but I’m posting out some of this here to get some commentary since I haven’t done much in the way of using interfaces.