2010-06-09 7 views
5

Ich arbeite an einem Framework, das ich versuche so stark wie möglich zu schreiben. (Ich arbeite mit PHP und nehme einige der Ideen, die ich von C# mag, und versuche, sie in diesem Rahmen zu verwenden.) Ich erstelle eine Collection-Klasse, die eine Sammlung von Domain-Objekten/-Objekten ist. Es ist irgendwie nach dem List<T> Objekt in .Net modelliert.PHP 'instanceof' schlägt mit der Klassenkonstante fehl

Ich bin auf ein Hindernis gestoßen, das mich daran hindert, diese Klasse zu tippen. Wenn ich eine UserCollection habe, sollte sie nur User-Objekte zulassen. Wenn ich eine PostCollection habe, sollte es nur Post-Objekte erlauben.

Alle Sammlungen in diesem Framework müssen bestimmte grundlegende Funktionen wie Hinzufügen, Entfernen, Iterieren haben. Ich habe eine Schnittstelle erstellt, aber festgestellt, dass ich Folgendes nicht tun konnte:

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

Dies brach seine Übereinstimmung mit der Schnittstelle. Aber ich kann die Schnittstelle nicht stark typisieren, weil dann alle Collections vom selben Typ sind. Also habe ich versucht, die folgenden:

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

Wenn ich versuche, diesen Code auszuführen, erhalte ich syntax error, unexpected T_STRING, expecting T_VARIABLE or '$' auf der instanceof Aussage. Ein wenig Forschung in das Problem und es sieht aus wie die Wurzel der Ursache ist $obj instanceof self ist gültig, um gegen die Klasse zu testen. Es scheint, dass PHP nicht die gesamte self::type Konstantenanweisung im Ausdruck verarbeitet. Hinzufügen von Klammern um den self::type Variable warfen einen Fehler in Bezug auf einem unerwarteten ‚(‘.

Ein offensichtliches Problem zu umgehen, die type Variable eine Konstante nicht zu machen ist. Der Ausdruck $obj instanceof $this->type funktioniert gut (wenn $type als Variable deklariert wird, natürlich)

Ich hoffe, dass es eine Möglichkeit gibt, das zu vermeiden, da ich den Wert als Konstante definieren möchte, um mögliche Änderungen in der Variablen später zu vermeiden.Jede Gedanken darüber, wie ich das erreichen kann, oder habe ich PHP in dieser Hinsicht an seine Grenzen gebracht? Gibt es eine Möglichkeit, self::this zu "entkommen" oder einzukapseln, so dass PHP bei der Verarbeitung nicht stirbt?

UPDATE Basierend auf dem Feedback unten dachte ich an etwas zu versuchen - der Code unten funktioniert! Kann irgendjemand an 1) einen Grund denken, dies nicht zu tun, 2) einen Grund, warum dies letztlich nicht funktionieren wird, oder 3) einen besseren Weg, dies zu schaffen?

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: Nach den obigen Code in Produktion setzen, stellt sich heraus, es funktioniert nicht. Ich habe keine Ahnung, wie es funktioniert hat, als ich es getestet habe, aber es funktioniert überhaupt nicht. Ich bin mit der Verwendung einer protected Variable fest, denke ich.

+0

ich glaube, ich antwortete 1 oder 2 - obwohl t Die Variable ist "geschützt", sie kann im Code noch geändert werden. Es gibt keine echte Sicherheit dafür, dass die Variable $ type nicht versehentlich geändert wird. Was ich mir erhofft hatte, war eine Versicherung dagegen. –

+0

Wenn ich richtig verstehe, geben Sie der instanceof-Operation eine Zeichenfolge ($ this-> type), wenn es nur ein Klassenname sein sollte (siehe http://php.net/manual/en/language.operators.type.php) . Ich denke, Sie sollten stattdessen "is_a" verwenden, da dies eine Zeichenfolge erwartet, die $ this-> type ist. – gacrux

+0

Keine wahre Aussage - sehen Sie sich Beispiel 5 auf der Seite an, mit der Sie verlinkt sind. –

Antwort

0

Dies funktioniert auch richtig, ein mit statischer:

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

Und tatsächlich, wollen Sie wahrscheinlich Ihre add() Methode auf der Collection Klasse ohnehin definieren, was bedeutet, Sie get_class() verwenden um einige zu erhalten Seltsamkeit mit self::type oder sogar self::$_type immer wollen die Basis Collection Klasse sowieso, so würde dies wahrscheinlich funktionieren zurückzukehren:

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

Ich bin überrascht, dieses Verhalten als gut, aber diese funktionieren sollte:

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

EDIT:

Sie

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

Aber Sie Einschalten des complicometer . Dies hat den zusätzlichen Aufwand, eine Instanz $type Variable für jede Instanz von PostCollection zu erstellen (und nein, Sie können static nicht einfach zur $type-Eigenschaft hinzufügen).

+0

Das gab mir eine Idee - ich habe meinen Beitrag aktualisiert. Vielen Dank! –

+0

@NathanLoding Dein neuer Code gab mir 'PHP Notice: Undefinierte Eigenschaft: PostCollection :: $ type'. – Artefacto

+0

Ich habe einen Tippfehler gemacht!Die Klassendefinition sollte "class PostCollection extends Collection" sein - ich werde es aktualisieren, guter Haken. –

3

Eine andere Lösung ist zu tun:

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

Nur weil es ist eine Konstante bedeutet nicht, Sie nicht in einer Variablen für einen Moment den Parser erfüllen setzen können.

+0

Das gab mir eine Idee - ich habe meinen Beitrag aktualisiert. Vielen Dank! –

+0

oder was ist falsch mit Klammern? '! ($ obj instanceof (self :: type))' – seanmonstar

+0

@seanmonstar - dieser exakte Ausdruck warf einen Fehler für mich in PHP. Hat es für dich funktioniert? Ich habe einen Fehler in Bezug auf 'unerwartet' (''. –

-2

Verwenden Sie die is_a-Funktion von PHP anstelle von instanceof, da eine Zeichenfolge als Klassenname erwartet wird.

+0

Das ist keine wahre Aussage. Schau dir Beispiel # 5 an ("Using instanceof mit anderen Variablen ") auf http://php.net/manual/en/language.operators.type.php. –

+0

Ah wahr, mein schlechter, danke für deinen Kommentar. – gacrux

2

Ich erstelle eine Collection-Klasse, die eine Sammlung von Domain-Objekten/Objekten ist. Es ist irgendwie nach dem List<T> Objekt in .Net modelliert.

Es ist generell keine gute Idee, eine Sprache in eine andere Sprache zu schreiben. Sie benötigen keine Sammlungen in PHP.

Wenn Sie diesen Weg fortsetzen, sollten Sie vielleicht die Tools von PHP in Erwägung ziehen. Zum Beispiel gibt es ArrayObject, von dem Sie die erforderlichen Methoden erben und überschreiben können, um sicherzustellen, dass nur richtig eingegebene Dinge in das Array gelangen. ArrayObjects kann überall in PHP verwendet werden, wo ein normales Array verwendet werden kann. Auch die zugrundeliegenden Teile wurden bereits für Sie geschrieben.

The rest of the Standard PHP Library kann für Sie von Interesse sein, insbesondere die Klasse SplObjectStorage.

+0

Außer ich sagte, es ist" irgendwie nachmodelliert. "Ich einen Bedarf für einen Container für mehrere Objekte desselben Typs haben und in der Lage sein müssen, einfach ein Objekt hinzuzufügen, zu entfernen, zu finden d iterieren durch sie - und es ist in einer PHP-App. Wenn dies eine .Net App wäre, würde ich ein 'List ' Objekt verwenden. In PHP habe ich das Vergnügen, meine eigene Variante zu erstellen. –

+0

Vielleicht möchten Sie meinen Post über den ersten Absatz hinaus lesen, während ich weiterführe, um zu erklären, wie PHP Ihnen vielleicht die Werkzeuge zur Verfügung stellt, die Sie brauchen, um dieses Verhalten zu erzeugen, ohne ein Konstrukt aus einer anderen Sprache zu implementieren. :) – Charles

+2

Die Optionen SplObjectStorage und ArrayObject sind nicht ganz das, was ich will. Ich sehe keinen Grund, nicht zu versuchen, ein Konstrukt von einer Sprache in eine andere zu erstellen, es sei denn, es gibt technische Gründe, warum diese nicht erreicht werden können. In diesem Fall ist das Erstellen einer Auflistungsklasse, die das List-Objekt in .Net nachahmt, innerhalb von PHP sehr gut möglich, das ist der stark typisierte Teil, der nicht existiert. Die Freude an PHP gegenüber .Net besteht darin, dass Sie diese Objekte selbst erstellen können. Ich schreibe nicht eine Sprache in einer anderen - ich erkunde Möglichkeiten in einer Sprache basierend auf Erfahrungen mit einer anderen Sprache. –

1

es sollte readly wie sein diese

public function add (ICollection $ obj) {

}

jetzt, wenn Sie versuchen, ein Objekt an die Funktion hinzuzufügen hinzufügen, dass keine Instanz von Icollection (das ist ein Beispiel), dann wird es fehlschlagen, bevor Sie sogar die instanceof überprüfen können.

+0

Das ist ein guter Gedanke - in diesem Fall wird es ein Entity-Objekt sein, aber eine gute Grundlage. –