2010-06-09 2 views
5

Я работаю над фреймворком, который я пытаюсь ввести так сильно, насколько это возможно. (Я работаю в PHP и беру некоторые из идей, которые мне нравятся на C#, и пытаюсь использовать их в этой структуре.) Я создаю класс Collection, который представляет собой совокупность объектов/объектов домена. Это похоже на модель List<T> в .Net.PHP 'instanceof' с ошибкой класса

Я столкнулся с препятствием, которое мешает мне печатать этот класс. Если у меня есть UserCollection, он должен включать только объекты User. Если у меня есть PostCollection, он должен разрешать только объекты Post.

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

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 объявлен как переменные, конечно).

Я надеюсь, что есть способ избежать этого, поскольку я хотел бы определить значение как константу, чтобы избежать любых возможных изменений в переменной позже. Любые мысли о том, как я могу это достичь, или есть ли способ «ускользнуть» или инкапсулировать 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(); 
    } 
} 
} 

UPDATE # 2: После ввода кода выше в производство, оказывается, что это не работает. Я понятия не имею, как это работает, когда я тестировал его, но он не работает вообще. Думаю, я застрял в использовании переменной protected.

+0

Я думаю, что я ответил на 1 или 2 - даже если т он переменный 'protected', он все равно может быть изменен в коде. Нет никакой реальной безопасности при этом так, что переменная '$ type' не будет изменена случайно. На что я надеялся, была страховка от этого. –

+0

Если я правильно понимаю, вы даете экземпляру операции строку ($ this-> type), когда она должна быть просто именем класса (см. Http://php.net/manual/en/language.operators.type.php) , Я думаю, вы должны использовать 'is_a', поскольку он ожидает строку, которая является типом $ this->. – gacrux

+0

Не истинное утверждение - посмотрите пример № 5 на странице, с которой вы связались. –

ответ

0

Это также работает правильно, используя статический:

<?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() метод на Collection класса в любом случае, это означает, что вам придется использовать 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()); 
1

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

$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(); 
     } 
    } 
} 

Но ты превращаешься на complicometer , У этого есть дополнительные накладные расходы на создание экземпляра переменной $type для каждого экземпляра PostCollection (и нет, вы не можете просто добавить static в свойство $type).

+0

Это дало мне представление - я обновил свой пост. Благодаря! –

+0

@Nathan Loding Ваш новый код дал мне PHP Замечание: Неопределенное свойство: PostCollection :: $ type'. – Artefacto

+0

Я сделал опечатку!Определение класса должно быть «class PostCollection extends Collection» - я обновлю его, поймаю. –

3

Другим решением является сделать:

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

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

+0

Это дало мне представление - я обновил свой пост. Благодаря! –

+0

или что не так в скобках? '! ($ obj instanceof (self :: type))' – seanmonstar

+0

@seanmonstar - это точное выражение бросило ошибку для меня в PHP. Это сработало для вас? Я получил сообщение об ошибке «неожиданно» («.» –

-2

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

+0

Это не истинное утверждение. Посмотрите пример # 5 («Использование instanceof с другими переменными ") на http://php.net/manual/en/language.operators.type.php. –

+0

Ах, правда, мое плохое, спасибо за ваш комментарий. – gacrux

2

Я создаю класс Collection, который представляет собой совокупность объектов/объектов домена. Это похоже на модель List<T> в .Net.

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

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

The rest of the Standard PHP Library может представлять для вас определенный интерес, в частности, класс SplObjectStorage.

+0

За исключением того, что я сказал, что это« похожее на модель ». имеют потребность в контейнере для нескольких объектов того же типа и могут легко добавлять, удалять, находить, d итерации через них - и это в приложении PHP. Если это было .Net-приложение, я бы использовал объект 'List '. В PHP я с удовольствием создаю свои собственные вариации. –

+0

Возможно, вы захотите прочитать мой пост за первым абзацем, так как я расскажу, как PHP уже может предоставить вам инструменты, необходимые для создания этого поведения, без реализации конструкции с совершенно другого языка. :) – Charles

+2

Параметры SplObjectStorage и ArrayObject не совсем то, что я хочу. Я не вижу причин не пытаться создать конструкцию с одного языка на другой, если нет технических причин, по которым они не могут быть выполнены. В этом случае создание класса коллекции, которое имитирует объект List в .Net, очень возможно в PHP, это строго типизированная часть, которой нет. Радость PHP над .Net заключается в том, что вы можете сами создавать эти объекты. Я не пишу один язык в другом - я изучаю возможности на одном языке, основываясь на опыте с другим языком. –

1

должно Readly быть, как это

общественная функция добавления (ICollection $ OBJ) {

}

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

+0

Это хорошая мысль - в этом случае это будет объект Entity, но хороший фундамент. –