PHP массив только с объектами определенного класса

У меня есть класс с именем Rule, и я собираюсь создать класс RuleContainer, который на самом деле массив объектов Rule.

Интересно, есть ли альтернатива созданию нового класса. Есть ли (современный) способ решения этой проблемы? То есть что-то вроде использования SPL для определения массив, который позволяет только добавлять объекты определенного класса.

Если нет, какой интерфейс я должен реализовать в своем классе RuleContainer?

4

Решение

Самый подходящий класс для вашей задачи будет SplObjectStorage, но он не учитывает типовые подсказки.

Я думаю, вы могли бы сделать следующее:

class RuleContainer extends SplObjectStorage
{
function attach(Rule $rule)
{
parent::attach($rule);
}

function detach(Rule $rule)
{
parent::detach($rule);
}
}

и так далее. Вы можете прочитать для SplObjectStorage интерфейс на php.net и решить, что вы будете использовать и что нужно переопределить.

2

Другие решения

В вашем случае я бы реализовал Iterator интерфейс в RuleContainer, как я делал несколько раз, когда мне нужно было Collection<T> как мы знаем из других (типизированных) языков. И в add(Rule $item) или же addItem(Rule $item) метод, который я бы удостоверился с определением типа аргумента (или используя instanceof) что добавляемый элемент имеет тип Rule,

1

В зависимости от шаблонов использования для вашего класса контейнера вам необходимо реализовать один или несколько из этих интерфейсов:

  • Iterator — использовать его как foreach($container as $key => $value);
  • Countable — за count($container);
  • ArrayAccess — за $container[$key] (установите это, получите это, проверьте, если это isset(), unset() Это);
1

Использование интерфейсов PHP массив-рутины

Вы можете достичь своей цели, например, ArrayAccess реализация. Вместе с Iterator это будет выглядеть так:

class ArrayStorage implements Iterator, ArrayAccess
{
private $holder = [];

private $instanceName;

public function __construct($instanceName)
{
if (!class_exists($instanceName)) {
throw new \Exception('Class '.$instanceName.' was not found');
}
$this->instanceName = $instanceName;
}
public function rewind()
{
reset($this->holder);
}

public function current()
{
return current($this->holder);
}

public function key()
{
return key($this->holder);
}

public function next()
{
next($this->holder);
}

public function valid()
{
return false !== $this->current();
}

public function offsetSet($offset, $value)
{
if (!($value instanceof $this->instanceName)) {
throw new \Exception('Storage allows only '.$this->instanceName.' instances');
}
if (is_null($offset)) {
$this->holder[] = $value;
} else {
$this->holder[$offset] = $value;
}
}

public function offsetExists($offset)
{
return isset($this->holder[$offset]);
}

public function offsetUnset($offset)
{
unset($this->holder[$offset]);
}

public function offsetGet($offset)
{
return isset($this->holder[$offset]) ? $this->holder[$offset] : null;
}
}

Procs

Так что — да, вы делаете instanceof проверьте явно, но конечный пользователь вашего класса не знает об этом. Можно будет работать только с действительными экземплярами в контексте этого хранилища (вы можете проверить эта скрипка за образец использования). Концепция как:

$storage = new ArrayStorage('Foo'); //define what we will accept
$storage[] = new Foo; //fine, [] array-writing
$storage['baz'] = new Foo; //fine, key set
foreach ($storage as $key => $value) {
echo($key. ' => '.PHP_EOL.var_export($value, 1).PHP_EOL);
}
//invalid, will not pass. Either throw exception or just ignore:
$storage['bee'] = new Bar;

Поведение конечной проверки на отказ зависит от вас, но, на мой взгляд, выбрасывать исключения — лучший выбор, так как они доступны, поэтому конечный пользователь может решить, что делать в этом случае. Дальнейший вариант может быть добавить Countable в хранилище, но это не изменит общей идеи.

И минусы

Недостаток — нет, вы не сможете как-то «напечатать». Хотя это и полезно, в документах вы все равно должны будете показать, какую сущность вы принимаете. С точки зрения общих языковых особенностей, есть массив RFC, Джо Уоткинс, который был предложен для PHP версии 5.6, но, к сожалению, не удалось. Может быть, это будет пересмотрено в следующих версиях релизов.

1

Ты можешь сделать RuleContainer себя (как ты говоришь) и делай всякие хитрости, чтобы принудительно применять его, но ты живешь в реальном мире, я живу в реальном мире, а ты просто не для этого нужен контейнерный объект, просто используйте массив.

Если ваша проблема просто одна из enforcement субъекта типа объекта а ля List<className>() вы не можете сделать это в PHP и, честно говоря, он является дискуссионным в тех языках, на которых он найден (я знаю, что за него скажут, но я все равно буду прав) // исключая его, можно еще больше уточнить назначение списка // Во всех Честно говоря, мои 20 с лишним лет программирования практически на всех языках (кроме машинного кода perl и fortran), я могу сказать вам, что такие конструкции просто не стоят человеческих накладных расходов, и сами по себе могут включать косвенные непреднамеренные нагрузки, превышающие их реальную ценность:

Простой компромисс: нет лени, начать именовать массив больше, чем что-то вроде tmpList и если вы абсолютны, решите, простое test в http://php.net/manual/en/function.get-class.php в начале forloops вы наверняка в конечном итоге используете

0
По вопросам рекламы [email protected]