"virtuelle" statische Funktion

Hallo!

Nachdem ich nicht annaehernd weiss wie ich mein Problem beschreiben soll
fehlen mir auch die Stichworte fuer eine Suche. Ich beschreib einmal was
ich gerne haette:

Ich habe eine (abstrakte) Klasse 'BasisModell'. Von diesem sind viele
andere Klasse abgeleitet (UserModell, ProduktModell, ...).

Nun will ich eine schnelle und einfache Moeglichkeit haben (ohne if und
Co) die einfach prueft, ob eine bestimmte Variable ein gueltiges Objekt
ist und wenn nicht, ganz einfach eine Exception wirft.

Das waere eine einfache Uebung, wenn ich diese (statische) Prueffunktion
in jede Klasse packen wuerde (UserModell, ProduktModell, ...).
Nachdem ich das aber nicht will, moechte ich es direkt in BasisModell
packen:

abstract class BasisModell
{
[...]
public static function check($obj)
{
$name = __MARKER__;
if(!($obj instanceof $name))
throw new IsNotValidException();
}
[...]
}

Wenn ich jetzt beispielsweise pruefen will, ob $foo auch wirklich ein
gueltiges ProduktModell ist, moechte ich einfach aufrufen:

ProduktModell::check($foo);

Prinzipiell wuerde das gehen, wenn ich statt __MARKER__ __CLASS__ setze.
Allerdings steht dann in $name 'BasisModell' drinnen und nicht
'ProduktModell'. Ich suche nun nach einer Moeglichkeit, wie ich in einer
*statischen* Funktion den Namen der letzten Klasse der
Ableitungshierarchie bekomme.

'self' könnte da ein Hinweis sein, allerdings geht das nur in
Zusammenhang mit dem '::' Operator.

Geht das? Wie?

lg,
Peter


PS: Ich koennte mir vorstellen dass es mit debug_backtrace gehen koennte,
aber eine etwas bessere Loesung waere schon fein ;-)
Peter Mairhofer [ Do, 30 August 2007 16:21 ] [ ID #1809031 ]

Re: "virtuelle" statische Funktion

Peter Mairhofer schrieb:
> Hallo!
>
> Nachdem ich nicht annaehernd weiss wie ich mein Problem beschreiben soll
> fehlen mir auch die Stichworte fuer eine Suche. Ich beschreib einmal was
> ich gerne haette:
>
> Ich habe eine (abstrakte) Klasse 'BasisModell'. Von diesem sind viele
> andere Klasse abgeleitet (UserModell, ProduktModell, ...).
>
> Nun will ich eine schnelle und einfache Moeglichkeit haben (ohne if und
> Co) die einfach prueft, ob eine bestimmte Variable ein gueltiges Objekt
> ist und wenn nicht, ganz einfach eine Exception wirft.
>
> Das waere eine einfache Uebung, wenn ich diese (statische) Prueffunktion
> in jede Klasse packen wuerde (UserModell, ProduktModell, ...).
> Nachdem ich das aber nicht will, moechte ich es direkt in BasisModell
> packen:
>
> abstract class BasisModell
> {
> [...]
> public static function check($obj)
> {
> $name = __MARKER__;
> if(!($obj instanceof $name))
> throw new IsNotValidException();
> }
> [...]
> }
>
> Wenn ich jetzt beispielsweise pruefen will, ob $foo auch wirklich ein
> gueltiges ProduktModell ist, moechte ich einfach aufrufen:
>
> ProduktModell::check($foo);
>
> Prinzipiell wuerde das gehen, wenn ich statt __MARKER__ __CLASS__ setze.
> Allerdings steht dann in $name 'BasisModell' drinnen und nicht
> 'ProduktModell'. Ich suche nun nach einer Moeglichkeit, wie ich in einer
> *statischen* Funktion den Namen der letzten Klasse der
> Ableitungshierarchie bekomme.
>
> 'self' könnte da ein Hinweis sein, allerdings geht das nur in
> Zusammenhang mit dem '::' Operator.
>
> Geht das? Wie?

Wieso prüfst du nicht einfach jedes Mal ($foo instanceof ProduktModell)?
Ansonsten hilft dir vielleicht http://de.php.net/get_class (ohne
Parameter) - hab jetzt aber nicht getestet, wie das mit den Ableitungen
umgeht.

Daniel
Daniel Fett [ Do, 30 August 2007 17:10 ] [ ID #1809035 ]

Re: "virtuelle" statische Funktion

Hi,

Daniel Fett <"news A" [at] fragcom.de> wrote in
news:46d6dddd$0$7691$9b4e6d93 [at] newsspool2.arcor-online.net:
> [...]
>
> Wieso prüfst du nicht einfach jedes Mal ($foo instanceof
> ProduktModell)? Ansonsten hilft dir vielleicht

Weil ich genau /das/ vermeiden will. Ich brauch die Checks x-fach und mag
nicht jedesmal die komplette if-Abfrage incl. "Rumpf" reinklopfen!

> http://de.php.net/get_class (ohne Parameter) - hab jetzt aber nicht
> getestet, wie das mit den Ableitungen umgeht.

Danke aber nein, leider. Gibt auch BasisModell aus statt ProduktModell :-
( :-(

mfg,
Peter
Peter Mairhofer [ Do, 30 August 2007 17:31 ] [ ID #1809036 ]

Re: "virtuelle" statische Funktion

Daniel Fett wrote:
> Wieso prüfst du nicht einfach jedes Mal ($foo instanceof ProduktModell)?
> Ansonsten hilft dir vielleicht http://de.php.net/get_class (ohne
> Parameter) - hab jetzt aber nicht getestet, wie das mit den Ableitungen
> umgeht.

Alle Funktionen welche Metainformationen über Klassen liefern benötigen
eine Instanzierte Klasse.

"get_class(self)" oder "get_class(parent)" liefern immer false.

Das Verhalten ist wohle "behavior by design"

<manual link="http://de3.php.net/manual/de/language.oop5.static.php">
Tatsächlich werden static Methodenaufrufe zum Kompilierungszeitpunkt
aufgelöst. Bei der Nutzung des expliziten Klassennamens ist die Methode
bereits gänzlich identifiziert und es kommen keine Vererbungsregeln zur
Anwendung. Falls der Aufruf durch self erfolgt, wird self in den
aktuellen Klassennamen übersetzt, d.h. die Klasse zu dem der Code
gehört. Hier kommen ebenfalls keine Vererbungsregeln zur Anwendung.
</manual>

Ohne einen entsprechenden Funktionsaufruf über die Kind-Klasse wird man
die Funktionalität nicht erfüllen können. Auch debug_backtrace() ist
keine Lösung, da die Kindklasse nicht im Trace auftaucht wenn eine
Muttermethode aufgerufen wird.

Mit Aufruf über die Kindklasse:
<code>
abstract class basic
{
static function check($classname, $object)
{
if (!$object instanceof $classname)
{
throw new Exception();
}
}
}

class myclass extends basic
{
static function check($object)
{
parent::check(__CLASS__, $object);
}
}

// ok
$foo = new myclass;
myclass::check($foo);
// throws exception
$foo = new stdClass;
myclass::check($foo);
</code>

Joe
Joe Scylla [ Do, 30 August 2007 17:37 ] [ ID #1809037 ]

Re: "virtuelle" statische Funktion

Joe Scylla <joe.scylla [at] gmail.com> wrote in news:fb6o38$3gi$00$1 [at] news.t-
online.com:
Hi auch dir,

> [...]
>
> Mit Aufruf über die Kindklasse:
> <code>
> abstract class basic
> {
> static function check($classname, $object)
> {
> if (!$object instanceof $classname)
> {
> throw new Exception();
> }
> }
> }
>
> class myclass extends basic
> {
> static function check($object)
> {
> parent::check(__CLASS__, $object);
> }
> }
>
> // ok
> $foo = new myclass;
> myclass::check($foo);
> // throws exception
> $foo = new stdClass;
> myclass::check($foo);
> </code>

Danke fuer deine Hinweise!

Offenbar geht das was ich will durch "behaviour by design" wirklich nicht
:-( Das mit debug_backtrace hab ich auch schon versucht und hat nicht
funktioniert. Selbst wenn ich in den Kindklassen eine

public static $__name = 'Product';

habe und in der Basisklasse mit self::$__name auslese bekomme ich ein
NULL (weil in der Basisklasse eben $__name nicht definiert ist).
Offenbar wird bei einem solchen Aufruf echt zum Compilezeitpunkt
aufgeloest, sodass es keine Chance gibt die tatsaechlich aufgerufene
Klasse zu bestimmen :-(

Dein Vorschlag ist im Endeffekt genau der den ich ja vermeiden wollte:
Jetzt muss ich in jeder Kindklasse (ProduktModell, UserModell, ...) die
Funktion implementieren!

Eine Frage zu deinem Beispiel: Wieso teilst du die Funktion hier auf
beide Klassen auf?

Wenn ich schon die Funktion in jede Kindklasse stecken muss waere es doch
effizienter die Ueberpruefung gleich in "MyClass" zu stecken oder?

Also

class myclass extends basic
{
[...]
static function check($obj)
{
if(!($obj instanceof __CLASS__))
{
throw Exception();
}
}
[...]
}

Alternativ, damit diese Methode wenigstens *immer* vorhanden ist und sein
muss, hab ich sie in der Basisklasse als abstrakt markiert:

abstract public static function check($obj);

mfg,
Peter
Peter Mairhofer [ Do, 30 August 2007 17:49 ] [ ID #1809039 ]

Re: "virtuelle" statische Funktion

Peter Mairhofer wrote:
> Dein Vorschlag ist im Endeffekt genau der den ich ja vermeiden wollte:
> Jetzt muss ich in jeder Kindklasse (ProduktModell, UserModell, ...) die
> Funktion implementieren!
>
> Eine Frage zu deinem Beispiel: Wieso teilst du die Funktion hier auf
> beide Klassen auf?
>
> Wenn ich schon die Funktion in jede Kindklasse stecken muss waere es doch
> effizienter die Ueberpruefung gleich in "MyClass" zu stecken oder?
>

Der Vorteil ist, dass die Funktionalität nur einmal vorhanden ist und
nur von allen Kindklassen aufgerufen wird. Der Aufruf in den Kindklassen
bleibt (voraussichtlich) gleich.

Die Logik der Fehlerbehandlung kann sich durchaus noch ändern (andere
Exception-Klasse, Error Log schreiben, etc). Und wenn sich die Logik
ändern soll muss man dies nur noch an einer Stelle machen.

Joe
Joe Scylla [ Do, 30 August 2007 18:04 ] [ ID #1809040 ]

Re: "virtuelle" statische Funktion

Peter Mairhofer schrieb:
> Hi,
>
> Daniel Fett <"news A" [at] fragcom.de> wrote in
> news:46d6dddd$0$7691$9b4e6d93 [at] newsspool2.arcor-online.net:
>> [...]
>>
>> Wieso prüfst du nicht einfach jedes Mal ($foo instanceof
>> ProduktModell)? Ansonsten hilft dir vielleicht
>
> Weil ich genau /das/ vermeiden will. Ich brauch die Checks x-fach und mag
> nicht jedesmal die komplette if-Abfrage incl. "Rumpf" reinklopfen!

Wieso keine Funktion dafür schreiben?

function check($foo, $bar)
{
if ($foo instanceof $bar)
{
//do stuff
}
}

Daniel
Daniel Fett [ Do, 30 August 2007 19:40 ] [ ID #1809042 ]
PHP » de.comp.lang.php.misc » "virtuelle" statische Funktion

Vorheriges Thema: http_get_request_headers nicht definiert?
Nächstes Thema: fgets funktioniert nicht. Warum?