Kernpunkte
Fiktive Szene: Hacker und Matrix
Das folgende Gespräch stammt aus einer Schnittszene aus der Matrix -Trilogie:
Merpheus: Neo, ich bin jetzt in der Matrix. Es tut mir leid, dass ich Ihnen diese schlechten Nachrichten erzählte, aber unser Agent -Tracking -PHP -Programm benötigt ein kurzes Update. Derzeit verwendet die PDO -Methode (mit String) die PDO -Methode (mit String), um den Status aller Matrixagenten aus unserer Datenbank zu erhalten. Wir müssen jedoch stattdessen Vorverarbeitungsabfragen verwenden.
Neo: Klingt gut, Morpheus. Kann ich eine Kopie des Programms erhalten?
Merphes: Kein Problem. Klonen Sie unser Repository und überprüfen Sie die Dateien agentmapper.php und index.php.
(Neo führt einige Git -Befehle aus, und der folgende Code erscheint vor ihm)
<?php namespace ModelMapper; class AgentMapper { protected $_adapter; protected $_table = "agents"; public function __construct(PDO $adapter) { $this->_adapter = $adapter; } public function findAll() { try { return $this->_adapter->query("SELECT * FROM " . $this->_table, PDO::FETCH_OBJ); } catch (Exception $e) { return array(); } } }
<?php use ModelMapperAgentMapper; // 一个 PSR-0 兼容的类加载器 require_once __DIR__ . "/Autoloader.php"; $autoloader = new Autoloader(); $autoloader->register(); $adapter = new PDO("mysql:dbname=Nebuchadnezzar", "morpheus", "aa26d7c557296a4e8d49b42c8615233a3443036d"); $agentMapper = new AgentMapper($adapter); $agents = $agentMapper->findAll(); foreach ($agents as $agent) { echo "Name: " . $agent->name . " - Status: " . $agent->status . "<br>"; }
nio: Morpheus, ich habe gerade die Dokumente bekommen. Ich habe die PDO unterklassifiziert und seine Query () -Methode überschrieben, damit vorverarbeitete Abfragen verwendet werden können. Aufgrund meiner Superkräfte sollte ich diesen Job sehr schnell beenden können. ruhig halten.
(Der Klang der Computertastatur widersetzt sich in der Luft)
nio: Morpheus, die Unterklasse ist zum Testen bereit. Überprüfen Sie es jederzeit.
(Murphys hat schnell auf seinem Laptop gesucht und die folgende Klasse gesehen)
<?php namespace LibraryDatabase; class PdoAdapter extends PDO { protected $_statement; public function __construct($dsn, $username = null, $password = null, array $driverOptions = array()) { // 检查是否传递了有效的 DSN if (!is_string($dsn) || empty($dsn)) { throw new InvalidArgumentException("The DSN must be a non-empty string."); } try { // 尝试创建一个有效的 PDO 对象并设置一些属性。 parent::__construct($dsn, $username, $password, $driverOptions); $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } catch (PDOException $e) { throw new RunTimeException($e->getMessage()); } } public function query($sql, array $parameters = array()) { try { $this->_statement = $this->prepare($sql); $this->_statement->execute($parameters); return $this->_statement->fetchAll(PDO::FETCH_OBJ); } catch (PDOException $e) { throw new RunTimeException($e->getMessage()); } } }
Merphes: Der Adapter sieht gut aus. Ich werde es sofort versuchen, um zu sehen, ob unser Agent Mapper aktive Agenten verfolgen kann, die durch die Matrix reisen. Viel Glück für mich.
(Murphys zögerte einen Moment und führte die vorherige Index.php -Datei aus, diesmal mit der Meisterwerks -Pdoadapter -Klasse von Neo. Dann ein Schrei!)
Merpheus: Neo, ich glaube du bist der "Retter"! Aber es gab einen schrecklichen tödlichen Fehler in meinem Gesicht, und die Nachrichten waren wie folgt:
<code>Catchable fatal error: Argument 2 passed to LibraryDatabasePdoAdapter::query() must be an array, integer given, called in path/to/AgentMapper on line (who cares?)</code>
(ein anderer Schrei)
neo: Was ist los? ! Was ist schief gelaufen? ! (mehr Schreie)
Merphes: Ich weiß es wirklich nicht. Oh, Agent Smith kommt jetzt, um mich zu fangen! (Die Kommunikation wurde plötzlich unterbrochen. Die lange Stille beendete das Gespräch, was darauf hindeutet, dass Morpheus unvorbereitet war und von Agent Smith schwer verletzt wurde.)
lsp repräsentiert keine faulen, dummen Programmierer
unnötig zu erwähnen, dass der obige Dialog fiktiv ist, aber das Problem ist zweifellos wahr. Wenn Neo nur ein oder zwei Wissen über das Liskov -Substitutionsprinzip (LSP) wie ein Hacker gelernt hätte, den er einst so berühmt war, konnte Agent Smith sofort verfolgt werden. Am wichtigsten ist, dass Morpheus vor der Bosheit des Wirkstoffs geschützt ist. Es war so schade für ihn. In vielen Fällen denken PHP -Entwickler jedoch fast dasselbe wie die frühere Meinung von Neo: LSP ist nichts anderes als ein puristisches theoretisches Prinzip, das in der Praxis nur wenig Anwendung hat. Aber sie gingen den falschen Weg. Obwohl die formale Definition von LSP schillernd (einschließlich mir) ist, besteht sein Kern darin, eine Hierarchie unklar definierter Klassen zu vermeiden, in denen Nachkommen sehr unterschiedlich sind als Basisklassenabstraktionen, die denselben Vertrag verwenden. Einfach ausgedrückt, legt LSP fest, dass beim Umschreiben von Methoden in Unterklassen die folgenden Anforderungen erfüllt sein müssen:
Jetzt können Sie die obige Liste erneut lesen (keine Sorge, ich werde warten) und Sie hoffen zu verstehen, warum dies sinnvoll ist. Wenn Sie zum Beispiel zurückkehren, behält der tödliche Fehler von NEO die Methode -Signatur einfach nicht gleich, wodurch der Vertrag mit dem Client -Code verstößt. Um dieses Problem zu lösen, kann die findAll () -Methode des Agent Mapper mit einigen bedingten Aussagen (offensichtlicher Code -Geruch) umgeschrieben werden, wie unten gezeigt:
<?php namespace ModelMapper; class AgentMapper { protected $_adapter; protected $_table = "agents"; public function __construct(PDO $adapter) { $this->_adapter = $adapter; } public function findAll() { try { return $this->_adapter->query("SELECT * FROM " . $this->_table, PDO::FETCH_OBJ); } catch (Exception $e) { return array(); } } }
Wenn Sie gut gelaunt sind, probieren Sie die Refactoring -Methode aus und es funktioniert gut, egal ob Sie ein nationales PDO -Objekt oder eine Instanz eines PDO -Adapters verwenden. Ich weiß, dass das rau klingt, aber es ist nur eine schnelle und einfache Lösung und verletzt das Prinzip des Öffnens und Schließens offen. Andererseits kann die Query () -Methode des Adapters so neu gestaltet werden, um der Signatur der Umschreibung der Elternklasse zu entsprechen. Dabei sollten auch alle anderen vom LSP angegebenen Bedingungen erfüllt sein. Kurz gesagt, dies bedeutet, dass das Umschreiben von Methoden mit Vorsicht durchgeführt werden sollte und nur aus sehr starken Gründen durchgeführt werden kann. In vielen Anwendungsfällen ist es unter der Annahme, dass die Schnittstelle nicht verwendet werden kann, eine Unterklasse, die nur ihre Basisklassenfunktionalität erweitert (und nicht überschreibt). Im Fall des PDO -Adapters von NEO funktioniert dieser Ansatz perfekt und wird den Client -Code auf keiner Ebene aufbrechen. Wie ich gerade sagte, gibt es eine effizientere, aber radikalere Lösung, die die Implementierung von Schnittstellen nutzt. Während frühere PDO -Adapter durch Vererbung erstellt wurden und unbestreitbar gegen die LSP -Vorschriften verstoßen, stammen die Nachteile tatsächlich aus der Art und Weise, wie die Agent Mapper -Klasse ursprünglich entworfen wurde. Tatsächlich hängt es von oben nach unten von einer konkreten Datenbankadapter-Implementierung und nicht von einem Schnittstellenvertrag ab. Und große OO -Kraft wurde seit der Antike gesagt, dies ist immer eine schlechte Sache. Wie wird die obige Lösung implementiert?
(Der Rest ähnelt dem Eingabetxt und kann bei Bedarf eingestellt und vereinfacht werden)
Das obige ist der detaillierte Inhalt vonDas Liskov -Substitutionsprinzip. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!