Text/Zusammengestellt von Zhu Xianzhong
1. Einführung
Glücklicherweise wurde die Objektüberladungstechnologie in PHP 5.0 eingeführt. In diesem Artikel wird die Möglichkeit einer Überladung der Methoden __call(), __set() und __get() untersucht. Nach einer kurzen Einführung in die Überladungstheorie gehen wir anhand von zwei Beispielen direkt zum Thema über: Das erste Beispiel besteht darin, eine persistente Speicherklasse zu implementieren.
2. Was ist Objektüberladung?
Wenn wir über Objektüberladung in PHP sprechen, müssen wir zwei Arten unterscheiden:
·Methodenüberladung
·Attributüberladung
Im Fall der Methodenüberladung müssen wir eine magische Methode __call() definieren, die einen generischen Aufruf einer undefinierten Methode implementiert in der entsprechenden Klasse. Diese allgemeine Methode wird nur aufgerufen, wenn Sie auf eine undefinierte Methode in der Klasse zugreifen möchten. Ohne Methodenüberladung führt das folgende Beispiel dazu, dass PHP eine schwerwiegende Fehlermeldung anzeigt: Aufruf der undefinierten Methode ThisWillFail::bar() in/some/directory/example.php in Zeile 9 und Abbruch der Ausführung des Programms:
< ?php
Klasse ThisWillFail {
öffentliche Funktion foo() {
return „Hallo Welt!“;
}
}
$class = new ThisWillFail;
$class->bar();
?>
Mit Hilfe der Methodenüberladung kann der Code diesen Aufruf abfangen und ordnungsgemäß verarbeiten.
Das Überladen von Eigenschaften ähnelt dem Überladen von Methoden. In diesem Fall leitet die Klasse Lese-/Schreibvorgänge auf Eigenschaften der Klasse um (auch Proxying genannt), die nicht explizit in der Klasse definiert sind. Die spezialisierten Methoden sind hier __set() und __get(). Abhängig von der Fehlerberichtsebene gibt der PHP-Übersetzer normalerweise entweder eine Benachrichtigung aus, wenn auf eine undefinierte Eigenschaft zugegriffen wird, oder er verschiebt die Variable und definiert sie möglicherweise. Wenn Sie die Attributüberladung verwenden, kann der Übersetzer __set() aufrufen, wenn er ein undefiniertes Attribut festlegt, und __get() aufrufen, wenn er auf einen undefinierten Attributwert zugreift.
Zusammenfassend lässt sich sagen, dass der Einsatz von Überlastungstechnologie die Softwareentwicklungszeit bei Verwendung dynamischer Sprachen wie PHP erheblich verkürzen kann.
An dieser Stelle wird die Theorie vorgestellt und im Folgenden die spezifische Codierung analysiert.
3. Beispiele für persistente Speicherklassen
Der folgende Code implementiert die oben erwähnte persistente Speicherklasse mit weniger als 50 Zeilen PHP-Code unter Verwendung der Attributüberladungstechnologie. Der Begriff „persistent“ bedeutet, dass die Klasse ein Element aus einer Datenstruktur beschreiben und mit dem zugrunde liegenden Speichersystem synchronisiert bleiben kann. In Bezug auf die Codierung kann externer Code Klassen verwenden, um eine Zeile aus einer Datenbanktabelle auszuwählen. Auf diese Weise können Sie bei laufendem Programm direkt auf die Attribute der Klasse zugreifen, um die Elemente in der Zeile zu manipulieren (Lesen/Abrufen). Am Ende des Skripts ist PHP dafür verantwortlich, die aktualisierten Zeilendaten zurück an die Datenbank zu senden.
Wenn Sie den folgenden Code sorgfältig studieren, können Sie besser verstehen, was eine Attributüberladung ist.
<?php
//Lade das <a href=" http://pear.php.net/package/DB/ "> DB-Paket</a> von PEAR
require_once "DB.php";
Klasse Persistable {
private $data = array();
private $table = "users";
öffentliche Funktion __construct($user) {
$this->dbh = DB::Connect("mysql://user:password@localhost/database");
$query = „SELECT id, name, email, land FROM“ .
$this->table . „ WHERE name = ?“
$this->data = $this->dbh->getRow($query, array($user),
DB_FETCHMODE_ASSOC);
}
öffentliche Funktion __get($member) {
if (isset($this->data[$member])) {
return $this->data[$member];
}
}
öffentliche Funktion __set($member, $value) {
//Die ID des Datensatzes ist schreibgeschützt, wenn ($member == "id") {
zurückkehren;
}
if (isset($this->data[$member])) {
$this->data[$member] = $value;
}
}
öffentliche Funktion __destruct() {
$query = „UPDATE“ . $this->table „SET name = ?,
email = ?, land = ? WHERE id = ?";
$this->dbh->query($query, $this->name, $this->email,
$this->country, $this->id);
}
}
$class = new Persistable("Martin Jansen");
$class->name = "John Doe";
$class->country = "Vereinigte Staaten";
$class->email = " [email protected] ";
?>
Das erste Problem, auf das Sie möglicherweise stoßen, ist __construct(), die neue Konstruktormethode, die in PHP 5 eingeführt wurde. In den Tagen von PHP 4 stimmten Konstruktoren immer mit ihren Klassennamen überein. Dies ist in PHP 5 nicht mehr der Fall. Sie müssen nicht viel über die Konstruktormethode wissen, außer dass ihr Aufruf eine Instanz einer Klasse erstellt und dass hier ein Parameter verwendet wird – eine Datenbank wird basierend auf diesem Parameter ausgeführt. Dieser Konstruktor weist die Abfrageergebnisse dem Klassenattribut $data zu.
Als nächstes definiert das Programm zwei spezielle Methoden __get() und __set(). Sie sollten bereits mit ihnen vertraut sein: __get() dient zum Lesen undefinierter Attributwerte und __set() zum Ändern undefinierter Attributwerte.
Dies bedeutet, dass diese spezialisierten Methoden immer dann, wenn eine undefinierte Eigenschaft aus einer persistenten Speicherklasse gelesen/geschrieben wird, für die Verwaltung der Informationen in der Eigenschaftsarray-Variablen $data verantwortlich sind, anstatt die Eigenschaften der Klasse direkt zu ändern (denken Sie daran: Die Variable $data enthält eine Zeile aus der Datenbank!).
Die letzte Methode in einer Klasse ist das Gegenteil von __construct() – der Destruktor __destruct(). PHP ruft den Destruktor während der „Skript-Shutdown-Phase“ auf, die normalerweise kurz vor dem Ende der Ausführung eines PHP-Skripts liegt. Der Destruktor schreibt die Informationen aus dem Attribut $data zurück in die Datenbank. Genau das bedeutet der bisherige Begriff Synchronisation.
Möglicherweise ist Ihnen aufgefallen, dass der Code hier das Datenbankabstraktionsschichtpaket von PEAR verwendet. Tatsächlich spielt es keine Rolle, dass auch die Kommunikation mit der Datenbank über andere Methoden das Thema dieses Artikels veranschaulichen kann.
Wenn Sie genau hinschauen, werden Sie feststellen, dass die Beschreibung dieser persistenten Speicherklasse relativ einfach ist. Das Beispiel betrifft nur eine Datenbanktabelle und berücksichtigt keine komplexeren Datenmodelle, wie z. B. die Verwendung von LEFT JOIN und anderen komplexen Datenbankbetriebstechniken. Sie müssen sich jedoch nicht darauf festlegen und können mit Hilfe der Eigenschaftsüberladung Ihr eigenes ideales Datenbankmodell verwenden. Mit nur wenig Code können Sie die Vorteile komplexer Datenbankfunktionen in dieser persistenten Speicherklasse nutzen.
Es gibt auch ein kleines Problem: Es wird kein Fehlerbehandlungsmechanismus eingeführt, wenn die Abfrage im Destruktor fehlschlägt. Es liegt in der Natur von Destruktoren, dass es in diesem Fall unmöglich ist, eine entsprechende Fehlermeldung anzuzeigen, da die Erstellung des HTML-Markups häufig endet, bevor PHP den Destruktor aufruft.
Um dieses Problem zu lösen, können Sie __destruct() in etwas wie saveData() umbenennen und diese Methode irgendwo im aufrufenden Skript manuell ausführen. Dies ändert nichts am Konzept der dauerhaften Speicherung für Klassen; es sind nur ein paar Zeilen Code mehr. Alternativ können Sie die Funktion error_log() im Destruktor verwenden, um die Fehlermeldung in einer systemweiten Fehlerprotokolldatei zu protokollieren.
So funktioniert die Eigenschaftsüberladung. Als nächstes besprechen wir die Methodenüberladung.
4. Beispiele für Methodenüberladung
1. Dynamische Getter/Setter-Methoden
Der folgende Code implementiert die „dynamischen“ Getter/Setter-Methoden, um die Klasse mithilfe der Methodenüberladung zu steuern. Lassen Sie es uns anhand des Quellcodes analysieren:
<?php
Klasse DynamicGetterSetter {
private $name = „Martin Jansen“;
private $starbucksdrink = "Caramel Cappuccino Swirl";
Funktion __call($method, $arguments) {
$prefix = strtolower(substr($method, 0, 3));
$property = strtolower(substr($method, 3));
if (empty($prefix) || empty($property)) {
zurückkehren;
}
if ($prefix == "get" && isset($this->$property)) {
return $this->$property;
}
if ($prefix == "set") {
$this->$property = $arguments[0];
}
}
}
$class = new DynamicGetterSetter;
echo "Name: " . $class->getName() "n";
echo „Lieblings-Starbucks-Geschmack:“ . $class->getStarbucksDrink() „nn“;
$class->setName("John Doe");
$class->setStarbucksDrink("Classic Coffee");
echo "Name: " . $class->getName() "n";
echo „Lieblings-Starbucks-Geschmack:“ . $class->getStarbucksDrink() „nn“;
?>
Offensichtlich sind die beiden Attribute $name und $starbucksdrink hier privat, was bedeutet, dass auf diese Attribute nicht von außerhalb der Klasse zugegriffen werden kann. In der objektorientierten Programmierung ist es weit verbreitet, öffentliche Getter/Setter-Methoden zu implementieren, um auf die Werte nicht öffentlicher Eigenschaften zuzugreifen oder diese zu ändern. Die Umsetzung ist mühsam und zeit- und arbeitsaufwändig.
Dieses Problem kann mithilfe der Methodenüberladung leicht gelöst werden. Anstatt Getter/Setter-Methoden für jede Eigenschaft zu implementieren, implementiert das Obige nur eine allgemeine __call()-Methode. Das bedeutet, dass PHP beim Aufruf einer undefinierten Getter/Setter-Methode wie setName() oder getStarbucksdrink() keinen schwerwiegenden Fehler generiert und abbricht, sondern stattdessen die magische Methode __call() ausführt (oder an sie delegiert).
Dies sind einige kurze Einführungen. Lassen Sie uns eine eingehende Analyse von __call() durchführen.
2. Detaillierte Analyse der __call()-Methode.
Der erste Parameter von __call() ist die ursprüngliche und unbestimmte Methode (z. B. setName). Der zweite Parameter ist ein eindimensionales Array mit einem numerischen Index, der alle ursprünglichen Methoden enthält . Parameter. Der Aufruf einer undefinierten Methode mit zwei Parametern („Martin“ und 42) erzeugt das folgende Array:
$class->thisMethodDoesNotExist("Martin", 42);
/Leitfaden zum zweiten Parameter von __call()
Array
(
[0] =>Martin
[1] => 42
)
Wenn innerhalb der Methode __call() die ursprüngliche Methode mit get oder set beginnt, muss eine Berechnung durchgeführt werden, um zu bestimmen, ob der Code eine Getter/Setter-Methode aufruft. Darüber hinaus analysiert diese Methode eine weitere Komponente des Methodennamens (mit Ausnahme der ersten drei Zeichen), da der letzte Teil der Zeichenfolge den Namen des Attributs darstellt, auf das der Getter/Setter verweist.
Wenn der Methodenname auf einen Getter/Setter hinweist, gibt die Methode entweder den entsprechenden Eigenschaftswert zurück oder legt den Wert des ersten Parameters der ursprünglichen Methode fest. Wenn nicht, unternimmt es nichts und führt das Programm weiter aus, als ob nichts passiert wäre.
3. Um das Ziel zu erreichen
, gibt es im Wesentlichen für jedes Attribut eine Methode, die es dem Code ermöglicht, jede Getter/Setter-Methode dynamisch aufzurufen. Dies ist praktisch, wenn Sie kurzfristig einen Programmprototyp entwickeln: Anstatt viel Zeit mit der Implementierung von Gettern/Settern zu verbringen, kann sich der Entwickler auf die Modellierung der API konzentrieren und sicherstellen, dass die Anwendung grundsätzlich korrekt ist. Die Einbindung der __call()-Methode in eine abstrakte Klasse ermöglicht Ihnen möglicherweise sogar die Wiederverwendung von Code in der zukünftigen PHP-Projektentwicklung
4. Zusätzlich zu den Mängeln
gibt es Vor- und Nachteile! Der obige Ansatz weist mehrere Nachteile auf: Größere Projekte verwenden möglicherweise Tools wie phpDocumentor, um die API-Struktur zu verfolgen. Bei der oben vorgestellten dynamischen Methode erscheinen natürlich nicht alle Getter/Setter-Methoden im automatisch generierten Dokument, was keiner weiteren Erläuterung bedarf.
Ein weiterer Nachteil besteht darin, dass Code außerhalb der Klasse auf jede private Eigenschaft innerhalb der Klasse zugreifen kann. Bei der Verwendung echter Getter/Setter-Methoden ist es möglich, zwischen privaten Eigenschaften, auf die durch externen Code zugegriffen werden kann, und „echten“ privaten Eigenschaften zu unterscheiden, die außerhalb der Klasse nicht sichtbar sind – da es eine Methodenüberladung gibt und wir über virtuelle Getter und Setter verfügen Methoden können eingesetzt werden.
5. Schlussfolgerung
In diesem Artikel werden die beiden Situationen der Objektüberladung in PHP 5.0 anhand von zwei Beispielen sorgfältig analysiert. Ich hoffe sehr, dass die Methode in diesem Artikel Ihnen helfen kann, die Effizienz der PHP-Programmierung zu verbessern. Gleichzeitig sollten Sie auch die Mängel dieser Methode klar erkennen!