PHP 'instanceof' in errore con la costante di class

Sto lavorando su un framework che sto cercando di digitare il più forte ansible. (Sto lavorando in PHP e sto prendendo alcune delle idee che mi piacciono da C # e sto cercando di utilizzarle in questo framework.) Sto creando una class Collection che è una raccolta di entity framework; / oggetti di dominio. È un po 'modellato rispetto all'object List<T> in .Net.

Ho incontrato un ostacolo che mi impedisce di digitare questa class. Se ho un UserCollection, dovrebbe consentire solo gli oggetti User in esso. Se ho un PostCollection, dovrebbe consentire solo oggetti Post.

Tutte le raccolte in questo framework devono avere alcune funzioni di base, come aggiungere, rimuovere, ripetere. Ho creato un'interface, ma ho scoperto che non potevo fare quanto segue:

 interface ICollection { public function add($obj) } class PostCollection implements ICollection { public function add(Post $obj) {} } 

Questo ha rotto la sua conformità all'interface. Ma non posso avere un'interface fortemente scritta perché tutte le raccolte sono dello stesso tipo. Quindi ho tentato quanto segue:

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

Quando tento di eseguire questo codice, ottengo l' syntax error, unexpected T_STRING, expecting T_VARIABLE or '$' instanceof . Una piccola ricerca sul problema e sembra che la radice della causa sia che $obj instanceof self sia valida per testare la class. Sembra che PHP non elabori l'intera espressione costante self::type nell'espressione. L'aggiunta di parentesi attorno alla variabile self::type ha generato un errore relativo a un imprevisto '('.

Una soluzione ovvia consiste nel non rendere costante la variabile di type . L'espressione $obj instanceof $this->type funziona bene (se $type è dichiarato come variabile, ovviamente).

Spero che ci sia un modo per evitarlo, dato che mi piacerebbe definire il valore come una costante per evitare qualsiasi ansible cambiamento nella variabile in seguito. Qualche idea su come posso get questo, o ho portto PHP al suo limite in questo senso? C'è un modo di "fuggire" o di incapsulare il self::this modo che PHP non muoia durante l'elaborazione?

AGGIORNAMENTO In base al feedback qui sotto, ho pensato a qualcosa da provare: il codice seguente funziona! Qualcuno può pensare a 1) una ragione per non farlo, 2) una ragione per cui alla fine non functionrà, o 3) un modo migliore per tirarlo fuori?

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

AGGIORNAMENTO # 2: Dopo aver inserito il codice sopra in produzione, risulta che non funziona. Non ho idea di come ha funzionato quando l'ho provato, ma non funziona affatto. Sono bloccato con l'utilizzo di una variabile protected , penso.

Anche questo funziona correttamente, usando una statica:

 <?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()); 

E in realtà, probabilmente vorrai definire il tuo metodo add() nella class Collection , il che significa che dovrai usare get_class() per aggirare qualche stranezza con self::type o anche self::$_type vuole sempre restituire comunque la class Collection base, quindi probabilmente functionrebbe:

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

Un'altra soluzione è quella di fare:

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

Solo perché è una costante non significa che non puoi metterlo in una variabile per un momento per soddisfare il parser.

Sto creando una class Collection che è una raccolta di entity framework; / oggetti di dominio. È un po 'modellato rispetto all'object List<T> in .Net.

Generalmente non è una buona idea scrivere una lingua in un'altra lingua. Non hai bisogno di collezioni in PHP.

Se continui su questa strada, forse dovresti prendere in considerazione l'utilizzo di strumenti forniti da PHP. Ad esempio, c'è ArrayObject , che puoi ereditare e sovrascrivere i methods richiesti per garantire che solo le cose digitate correttamente entrino nell'arrays. ArrayObjects può essere utilizzato ovunque in PHP, where è ansible utilizzare un arrays normale. Inoltre, i bit e i pezzi sottostanti sono già stati scritti per te.

Il resto della libreria PHP standard potrebbe essere di qualche interesse per te, in particolare la class SplObjectStorage .

Sono sorpreso anche da questo comportmento, ma questo dovrebbe funzionare:

 $type = self::type; if(!($obj instanceof $type)) { throw new UhOhException(); } 

MODIFICARE:

Potresti farlo

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

Ma stai accendendo il complicometro. Questo ha l'overhead aggiuntivo di creare una variabile di $type istanza per each istanza di PostCollection (e no, non si può semplicemente aggiungere static alla properties; $type ).

dovrebbe essere prontamente così

function pubblica add (ICollection $ obj) {

}

ora se provi ad aggiungere un object alla function add che non è un'istanza di Icollection (questo è un esempio) allora fallirà, prima ancora di controllare usando l'instanceof.

Prova a usare la function is_a di PHP invece di instanceof in quanto si aspetta una string come nome della class.