Statische Methode einer abstrakten Klasse aufrufen
Mastershrimp
- php
0 hev0 Mastershrimp0 hev
0 Christian Seiler
Heyho!
Der Titel ist nicht ganz korrekt: Eigentlich meine ich,
Wie rufe ich eine statische Methode einer Klasse auf, die diese statische Methode von einer abstrakten Klasse aufgezwungen bekommt? Der Haken ist, der Aufruf soll aus der abstrakten Klasse erfolgen - die ja zum Implementierungszeitpunkt noch nicht ihre konkreten erbenden Klassen kennt.
Code-Bsp (nur schnell dahingetippt, muss nicht funktionieren):
abstract class AbstrakteKlasse {
public function eineObjektMethode() {
XXX::eineAbstrakteStatischeMethode();
}
abstract public static function eineAbstrakteStatischeMethode();
}
class Weihnachten extends AbstrakteKlasse {
public static function eineAbstrakteStatischeMethode() {
echo("Bald ist Weihnachten");
}
}
class Ostern extends AbstrakteKlasse {
public static function eineAbstrakteStatischeMethode() {
echo("Bald ist Ostern");
}
}
$w = new Weihnachten();
$w->eineObjektMethode(); // Soll "Bald ist Weihnachten" ausgeben
Der Aufruf müsste ja jetzt eigentlich anstelle des "XXX" "Weihnachten" haben, also Weihnachten::eineAbstrakteStatischeMethode();
Nur wie komm ich an "Weihnachten"?
__CLASS__::eineAbstrakteStatischeMethode(); ists nicht, war mal so'n Versuch ohne groß zu wissen obs Sinn macht
Auch $self::eineAbstrakteStatischeMethode(); wirf die lustige "unexpected T_PAAMAYIM_NEKUDOTAYIM"-Fehlermeldung aus
Jemand ne andere Idee?
Gruß
Mastershrimp
Vielleicht AbstrakteKlasse als XXX einsetzen?!
Heyho!
Vielleicht AbstrakteKlasse als XXX einsetzen?!
:D
Ja. In diesem konkreten Fall mit Sicherheit. Das ist aber nicht Sinn der Sache ;)
Der Sinn einer abstrakten Klasse ist ja, dass diese ihre erbenden Klassen noch nicht kennt. Ich brauche also einen Platzhalter für "XXX". Etwas, das den Namen der aktuellen (erbenden) Klasse einsetzt.
Gruß
Mastershrimp
Ich brauche also einen Platzhalter für "XXX". Etwas, das den Namen der aktuellen (erbenden) Klasse einsetzt.
So gehts auch:
public function eineObjektMethode() {
call_user_func(get_class($this) . '::eineAbstrakteStatischeMethode');
}
etwas nervig finde ich aber damit kannst du erstmal arbeiten...
Hallo,
Du suchst etwas, das sich "Late Static Binding" nennt, was in PHP erst ab 5.3 implementiert werden wird (so wie's aussieht).
Wobei ich bei Deinem Beispiel nicht ganz verstehe, warum die abstrakte Methode überhaupt static sein muss? Du kannst doch genausogut eine normale Methode, die nicht static ist nehmen, dann hast Du die Probleme nicht.
Viele Grüße,
Christian
Heyho!
Interessant! Hm, aber dann werde ich mich wohl mit einem Workaround begnügen müssen.
Wobei ich bei Deinem Beispiel nicht ganz verstehe, warum die abstrakte Methode überhaupt static sein muss? Du kannst doch genausogut eine normale Methode, die nicht static ist nehmen, dann hast Du die Probleme nicht.
Ja, das stimmt schon. Die Methode muss aber halt static sein ;)
Konkret gehts darum, dass ich für diverse Objekte (accounts, institutionen, etc) eine Klasse GenericObject habe, die bestimmte Methoden, die von allen Klassen gleich benutzt werden, bereitstellt.
Zu diesen Methoden zählt auch eine statische Methode "validateValue($attribute, $value)" die prüft, ob für ein gegebenes Attribut ein gegebener Wert zulässig ist. So kann ich sämtliche Überprüf-Funktionen schön kapseln.
Dann gibt es weiterhin eine Objekt-Methode, die die statische Methode einsetzt. Als Beispiel: setValue($attribute, $newValue);
Diese wird z.B. so aufgerufen: $myAccount->setValue("name", "Peter");
Die setValue überprüft nun intern, ob der Wert "Peter" für das Attribut "name" zulässig ist.
Klar, dieses Szenario ginge auch über eine Objektmethode.
Aber was ist mit einer Methode createNewAccount($name, $gender, $tel, $fax, ...)? Die ist ja auch statisch, weils noch kein Objekt gibt (es wird ja erst jetzt angelegt). Und wegen dieser Methode muss ich dann halt auch die validateValue() static haben.
Oder kann man das irgendwie eleganter lösen?
Eine Möglichkeit wäre halt jetzt, dass ich die setValue() von der abstrakten Klasse in die konkrete Klasse verschiebe. Dann hab ich halt n bisschen redundanten Code, aber das ließe sich noch einrichten. Ist ja nur n Zweizeiler.
Gruß
Mastershrimp
Hallo!
Aber was ist mit einer Methode createNewAccount($name, $gender, $tel, $fax, ...)? Die ist ja auch statisch, weils noch kein Objekt gibt (es wird ja erst jetzt angelegt). Und wegen dieser Methode muss ich dann halt auch die validateValue() static haben.
Warum rufst Du die validateValue() nicht im Konstruktor auf? Wenn die fehlschlägt, kann der Konstruktor ja eine Exception werfen. Und selbst wenn Du Exceptions an sich nicht sonderlich magst und keine Exceptions zurückgeben willst, kannst Du ja immer noch sowas machen wie:
function createNewAccount (...) {
try {
$blub = new ... (...);
} catch (MeineExceptionKlasse $e) {
return false; // validierung fehlgeschlagen
}
}
(Oder, falls Du eh Exceptions weitergibst, lasse den try/catch-Block einfach weg.)
Viele Grüße,
Christian
Heyho!
Hm ich glaube wir setzen den Konstruktor anders ein. Bei mir sieht der Konstruktor für ein Account-Objekt vereinfacht so aus:
public function __construct($accountID) {
$query = mysql_query("SELECT name, email, fax FROM tab_accounts WHERE accountID = '$accountID' LIMIT 1");
$data = mysql_fetch_object($query);
$this->name = $data->name;
$this->email = $data->email;
//...weitere Attribute
}
Erstellen (sprich: in der DB speichern) tu ich ein Account Objekt mit der statischen Methode createAccount($name, $email, $fax, ...);
Benutzt du den Konstruktor zum Erstellen (d.h. physischen Speichern in der DB) eines Account-Objekts? Ich benutz den nur um mir das Objekt aus den DB-Daten zu generieren....Ka, hat mir mal einer so gezeigt und macht find ich Sinn.
Ich glaub ich lös das obenstehende Problem so, dass ich eine Objektmethode private function validateValueHelper() in die konkrete Objektklasse implementiere, die die statische Methode aufruft. Da müsste ja $self funktionieren glaub ich (noch nicht getestet)
private function validateValueHelper($attribute, $newValue) {
return $self::validateValue($attribute, $newValue);
}
Dann trigger ich aus der setValue() diese Helper-Methode, die dann die statische Methode aufruft. Da setValue() eine Objektmethode ist, klappt das ja auch (sofern $self so funktioniert wie ichs mir erhoffe, nämlich dass $self::validateValue(...) in der eigenen Klasse nach einer statischen Methode validateValue() sucht und diese aufruft).
Für die anderen Fälle kann ich die validateValue() ja eh direkt aufrufen.
Macht Sinn? ;)
Mal am WE testen....Muss noch für Klausuren lernen *brrrr*
Gruß
Mastershrimp
echo $begrüßung;
Benutzt du den Konstruktor zum Erstellen (d.h. physischen Speichern in der DB) eines Account-Objekts?
Ich benutz den nur um mir das Objekt aus den DB-Daten zu generieren....Ka, hat mir mal einer so gezeigt und macht find ich Sinn.
Erstellen (sprich: in der DB speichern) tu ich ein Account Objekt mit der statischen Methode createAccount($name, $email, $fax, ...);
Warum erstellst du nicht ein Account-Objekt zunächst unabhängig von der Herkunft seiner Daten über den Konstruktor? Du kannst dann eine nicht-statische Methode aufrufen um die Werte zu testen.
Ein Vorschlag wäre, dem Konstruktor die Daten als Parameter zu übergeben. Erstellst du einen Account zu Fuß, übergibst du die Werte direkt. Für den Fall der Herkunft aus der Datenbank könntest du eine statische Methode verwenden, die nach dem Lesen der Ergebnismenge ein Objekt mittels der an den Konstruktor übergebenen Daten erstellt.
Oder du leitest eine spezialisierte Klasse von der allgemeinen Account-Klasse ab, deren Konstruktor die Daten aus der DB holt und dann dem geerbten Construktor übergibt.
Noch eine weitere Möglichkeit wäre wie folgt:
In anderen Sprachen kann man mehrere Konstruktoren erstellen, wenn sich die Signaturen eindeutig voneinander unterscheiden. Vom Prinzip her so:
__construct(string $name, string $password, string $email)
__construct(int $id)
Der erste erstellt ein Objekt aus den übergebenen Daten, der zweite eins aus einem Datensatz. Für PHP kann man das so nicht implementieren.
__construct($name, $password = null, $email = null)
Aber man kann auswerten, ob diesem Konstruktor nur ein Parameter übergeben wurden, und dann den Wert in $name als ID ansehen, um damit den Datensatz aus der DB zu holen. Leider sieht das etwas unsauber aus, aber anders geht es in PHP nicht. Hier kommt es auf eine gute Dokumentation der beiden Aufrufvarianten an.
Was auch immer du machst, versuch es so wenig kompliziert wie nötig zu gestalten.
echo "$verabschiedung $name";
Heyho!
Hmmm alles ganz nette Ideen - aber ich find meine Methode bis jetzt am praktischsten. Und auch semantisch irgendwie am sprechendsten. Naja, ist wohl Geschmackssache. Wie gesagt, zur Not implementiere ich diese statische Methode (die hier das Problem macht) einfach in jede Klasse. Ändern wird sich da nichts mehr und sind nur 3 Zeilen.
So'n riesen Vererbungschaos machen nur um 2 Konstruktoren zu haben....ich weiß nicht. Naja ich schau mal wie weit ich nächste Woche komme und rollte die Frage dann evtl nochmal auf :)
Vielen Dank für eure Antworten!!
Gruß
Mastershrimp