Я работаю над платформой, которую я пытаюсь ввести так сильно, как я возможно могу. (Я работаю в PHP и беру некоторые идеи, что мне нравится от C# и пытающийся использовать их в этой платформе.) я создаю класс Набора, который является набором доменных объектов/объектов. Это отчасти смоделировано после List<T>
объект в .NET.
Я столкнулся с препятствием, которое препятствует тому, чтобы я ввел этот класс. Если у меня есть UserCollection, он должен только позволить Пользовательские объекты в него. Если у меня есть PostCollection, он должен только позволить объекты Сообщения.
Все Наборы в этой платформе должны иметь определенные основные функции, те, которые добавляют, удаляют, выполняют итерации. Я создал интерфейс, но нашел, что не мог сделать следующего:
interface ICollection { public function add($obj) }
class PostCollection implements ICollection { public function add(Post $obj) {} }
Это повредилось, это - соответствие интерфейсу. Но у меня не может быть интерфейса, со строгим контролем типов, потому что затем все Наборы имеют тот же тип. Таким образом, я делал попытку следующего:
interface ICollection { public function add($obj) }
abstract class Collection implements ICollection { const type = 'null'; }
class PostCollection extends Collection {
const type = 'Post';
public function add($obj) {
if(!($obj instanceof self::type)) {
throw new UhOhException();
}
}
}
Когда я пытаюсь выполнить этот код, я добираюсь syntax error, unexpected T_STRING, expecting T_VARIABLE or '$'
на instanceof
оператор. Немного исследования проблемы и похоже, что корень причины - это $obj instanceof self
допустимо для тестирования против класса. Кажется, что PHP не обрабатывает все self::type
постоянный оператор в выражении. Добавление круглых скобок вокруг self::type
переменная бросила ошибку относительно неожиданного' ('.
Очевидное обходное решение не должно делать type
переменная константа. Выражение $obj instanceof $this->type
работает просто великолепно (если $type
объявляется как переменная, конечно).
Я надеюсь, что существует способ избежать этого, поскольку я хотел бы определить значение как константу для предотвращения любого возможного изменения в переменной позже. Какие-либо мысли о том, как я могу достигнуть этого, или сделать, я беру PHP к, он - предел в этом отношении? Есть ли способ "выйти" или инкапсулировать self::this
так, чтобы PHP не умирал при обработке его?
ОБНОВЛЕНИЕ На основе обратной связи ниже, я думал о чем-то для попытки - код ниже работ! Может любой думать 1) о причине не сделать это, 2) о причине, это не будет в конечном счете работать, или 3) о лучшем способе осуществить это?
interface ICollection { public function add($obj) }
abstract class Collection { const type = null; protected $type = self::type; }
class PostCollection extends Collection {
const type = 'Post';
public function add($obj) {
if(!($obj instanceof $this->type)) {
throw new UhOhException();
}
}
}
ОБНОВЛЕНИЕ № 2: После помещения кода выше в производство, оказывается, что это не работает. Я понятия не имею, как это работало, когда я протестировал его, но это не работает вообще. Я застреваю с использованием a protected
переменная, я думаю.
Это также работает правильно, используя static:
<?php
interface ICollection {
public function add($obj);
}
abstract class Collection implements ICollection {
static protected $_type = 'null';
}
class PostCollection extends Collection {
static protected $_type = 'Post';
public function add($obj) {
if(!($obj instanceof self::$_type)) {
throw new UhOhException();
}
}
}
class Post {}
$coll = new PostCollection();
$coll->add(new Post());
И на самом деле вы, вероятно, захотите определить свой метод add ()
в коллекции
class в любом случае, что означает, что вам придется всегда использовать get_class ()
, чтобы обойти некоторые странности с self :: type
или даже self :: $ _ type
все равно желая вернуть базовый класс Collection
, так что это, вероятно, сработает:
abstract class Collection implements ICollection {
const type = 'null';
public function add($obj) {
$c = get_class($this);
$type = $c::type;
if(!($obj instanceof $type)) {
throw new UhOhException();
}
}
}
class PostCollection extends Collection {
const type = 'Post';
}
class Post {}
$coll = new PostCollection();
$coll->add(new Post());
Я создаю класс Collection, который представляет собой набор сущностей / объектов предметной области. Это как бы по образцу объекта
List
в .Net.
Как правило, писать с одного языка на другом - плохая идея. Коллекции в PHP не нужны.
Если вы собираетесь продолжать идти по этому пути, возможно, вам следует рассмотреть возможность использования инструментов, предоставляемых вам PHP. Например, есть ArrayObject , от которого вы можете унаследовать и переопределить требуемые методы, чтобы гарантировать, что в массив попадают только правильно набранные объекты. ArrayObjects можно использовать в любом месте PHP, где можно использовать обычный массив. Кроме того, основные части уже написаны для вас.
Остальная часть стандартной библиотеки PHP может вас заинтересовать, в частности, класс SplObjectStorage .
Попробуйте использовать функцию PHP is_a вместо instanceof, поскольку она ожидает строку в качестве имени класса.
Другой обходной путь:
$type = self::type;
if (!($obj instanceof $type))
То, что это константа, не означает, что вы не можете поместить ее в переменную, чтобы удовлетворить парсер.
Я тоже удивлен таким поведением, но это должно работать:
$type = self::type;
if(!($obj instanceof $type)) {
throw new UhOhException();
}
EDIT:
Можно сделать
abstract class Collection {
const type = null;
protected $type = self::type;
}
class PostCollection extends Collection {
const type = "User";
public function add($obj) {
if(!($obj instanceof $this->type)) {
throw new WhateverException();
}
}
}
Но вы включаете усложнитель. Это создаст дополнительные накладные расходы на создание переменной экземпляра $type
для каждого экземпляра PostCollection
(и нет, вы не можете просто добавить static
к свойству $type
).
это должно выглядеть примерно так
public function add(ICollection $obj){
}
теперь, если вы попытаетесь добавить объект в функцию add, который не является экземпляром Icollection (это пример), то она завершится неудачей, даже не дождавшись проверки с помощью instanceof.