У меня есть класс, более конкретный репозиторий. В этом хранилище будут храниться мои валидаторы, чтобы я мог связаться с ними, когда захочу. В настоящее время это выглядит так:
class ValidatorRepository {
private $validators;
public function __construct() {
$this->validators = array();
}
public function get($key) {
return $this->validators[$key];
}
public function add($key, iValidator $value) {
$this->validators[$key] = $value;
}
public static function getInstance() {
//(...)
}
}
И с этим классом я хотел бы сделать что-то вроде этого:
$vr = ValidatorRepository::getInstance();
$vr->add("string", new StringValidator());
Я могу вставить что-то еще, чем экземпляр объекта, если это к лучшему.
.. и позже, в другом месте;
$vr = ValidatorRepository::getInstance();
$vr->get("string"); // should return a *new* instance of StringValidator.
Идея состоит в том, что ValidatorRepository НЕ должен знать о классах до их добавления. Это работает нормально, пока я возвращаю текущий объект.
Но вместо этого мне нужен новый объект класса. Я мог бы это сделать, поставив статическую функцию getInstance() в каждом валидаторе или каким-то образом использовать eval, но я надеюсь, что может быть другой, менее уродливый способ.
Я считаю, что вы должны сделать что-то такое простое:
public function add( $key, iValidator $value ) {
$this->validators[ $key ] = get_class( $value ); // this call can be moved to get() if you wish
}
public function get( $key ) {
return new $this->validators[ $key ];
}
get_class() учитывает пространства имен, поэтому, если вы используете пространства имен, все равно будет хорошо.
Это может быть несколько более гибкий подход:
public function add( $key, iValidator $value ) {
$this->validators[ $key ] = $value;
}
public function get( $key, $new = true ) {
if ($new) {
$class = get_class( $this->validators[ $key ] );
$class = new $class;
} else {
$class = $this->validators[ $key ];
}
return $class;
}
Вместо этого вы должны использовать либо наследование:
abstract class Validated {
public function validate(){
foreach(self::VALIDATIONS as $val) {
// ...
}
}
}
class Person extends Validated {
protected $name;
const VALIDATIONS = array(
'name' => array( 'length' => new LengthValidator(15) )
);
}
или черт:
trait Validated {
function validate(){
// ...
}
}
class Person {
use Validated;
}
Перемещение всей логики проверки в один класс нарушает принцип единого ответственно, поскольку он ответственен за проверку всех классов, которые его используют. Он быстро выйдет из-под контроля.
Обратите внимание, что я использовал константу для проверки - вам редко приходится менять правила проверки для класса во время выполнения.