PHP 'instanceof' переставший работать с постоянным классом

Я работаю над платформой, которую я пытаюсь ввести так сильно, как я возможно могу. (Я работаю в 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 переменная, я думаю.

5
задан Nathan Loding 13 June 2010 в 00:46
поделиться

6 ответов

Это также работает правильно, используя 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());
0
ответ дан 14 December 2019 в 13:27
поделиться

Я создаю класс Collection, который представляет собой набор сущностей / объектов предметной области. Это как бы по образцу объекта List в .Net.

Как правило, писать с одного языка на другом - плохая идея. Коллекции в PHP не нужны.

Если вы собираетесь продолжать идти по этому пути, возможно, вам следует рассмотреть возможность использования инструментов, предоставляемых вам PHP. Например, есть ArrayObject , от которого вы можете унаследовать и переопределить требуемые методы, чтобы гарантировать, что в массив попадают только правильно набранные объекты. ArrayObjects можно использовать в любом месте PHP, где можно использовать обычный массив. Кроме того, основные части уже написаны для вас.

Остальная часть стандартной библиотеки PHP может вас заинтересовать, в частности, класс SplObjectStorage .

2
ответ дан 14 December 2019 в 13:27
поделиться

Попробуйте использовать функцию PHP is_a вместо instanceof, поскольку она ожидает строку в качестве имени класса.

-2
ответ дан 14 December 2019 в 13:27
поделиться

Другой обходной путь:

$type = self::type;
if (!($obj instanceof $type))

То, что это константа, не означает, что вы не можете поместить ее в переменную, чтобы удовлетворить парсер.

3
ответ дан 14 December 2019 в 13:27
поделиться

Я тоже удивлен таким поведением, но это должно работать:

$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).

2
ответ дан 14 December 2019 в 13:27
поделиться

это должно выглядеть примерно так

public function add(ICollection $obj){

}

теперь, если вы попытаетесь добавить объект в функцию add, который не является экземпляром Icollection (это пример), то она завершится неудачей, даже не дождавшись проверки с помощью instanceof.

1
ответ дан 14 December 2019 в 13:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: