mata teras
adegan fiksyen: penggodam dan matriks
Perbualan berikut datang dari adegan potong dari trilogi Matrix:Merpheus: Neo, saya dalam matriks sekarang. Maaf untuk memberitahu anda berita buruk ini, tetapi ejen kami menjejaki program PHP memerlukan kemas kini yang cepat. Ia kini menggunakan kaedah pertanyaan PDO () (dengan rentetan) untuk mendapatkan keadaan semua ejen matriks dari pangkalan data kami, tetapi kami perlu menggunakan pertanyaan preprocessing sebaliknya.
Neo: Bunyi baik, Morpheus. Bolehkah saya mendapatkan salinan program?
Merphes: Tiada masalah. Klon repositori kami dan periksa fail AgentMapper.php dan index.php.
(Neo melaksanakan beberapa arahan git, dan kod berikut muncul di hadapannya)
<?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>"; }
(bunyi papan kekunci komputer bergema di udara)
nio: Morpheus, subclass bersedia untuk ujian. Semaknya bila -bila masa.
(Murphys mencari dengan cepat di komputer ribanya dan melihat kelas berikut)
<?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()); } } }
(Murphys teragak -agak seketika, menjalankan fail index.php sebelumnya, kali ini menggunakan kelas karya PDOADAPTER NEO. Kemudian, jeritan!) Merpheus: Neo, saya percaya anda adalah "Juruselamat"! Tetapi ada kesilapan maut yang dahsyat di wajah saya, dan berita itu adalah seperti berikut:
(satu lagi jeritan)
<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>
neo: Apa yang salah? ! Apa yang salah? ! (lebih banyak jeritan)
Merphes: Saya tidak tahu. Oh, Agent Smith akan datang untuk menangkap saya sekarang! (komunikasi tiba -tiba terganggu. Keheningan yang panjang mengakhiri perbualan, menunjukkan bahawa Morpheus ditangkap dan cedera parah oleh Agent Smith.)
LSP tidak mewakili pengatur malas, bodohtidak perlu dikatakan, dialog di atas adalah fiksyen, tetapi masalahnya sudah pasti benar. Sekiranya Neo hanya belajar satu atau dua keping pengetahuan tentang Prinsip Penggantian Liskov (LSP) seperti penggodam yang pernah dia terkenal seperti yang pernah dia lakukan, Agent Smith dapat dikesan dengan segera. Paling penting, Morpheus dilindungi dari kebencian ejen. Sayang sekali untuknya. Walau bagaimanapun, dalam banyak kes, pemaju PHP berfikir tentang LSP hampir sama dengan pendapat sebelumnya Neo: LSP hanyalah prinsip teoretikal purist yang mempunyai sedikit permohonan dalam amalan. Tetapi mereka pergi dengan cara yang salah. Walaupun definisi formal LSP mempesonakan (termasuk saya), terasnya adalah untuk mengelakkan hierarki kelas yang tidak jelas di mana keturunan berkelakuan sangat berbeza dari abstrak kelas asas yang menggunakan kontrak yang sama. Ringkasnya, LSP menetapkan bahawa apabila menulis semula kaedah dalam subkelas, keperluan berikut mesti dipenuhi:
tandatangannya mesti sepadan dengan tandatangan kelas induk
<?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(); } } }
Jika anda berada dalam mood yang baik, cuba kaedah refactoring dan ia akan berfungsi dengan baik, sama ada menggunakan objek PDO asli atau contoh penyesuai PDO. Saya tahu ini kedengarannya kasar, tetapi ia hanya membetulkan cepat dan mudah, dan ia secara terang -terangan melanggar prinsip pembukaan dan penutupan. Sebaliknya, kaedah pertanyaan penyesuai () boleh dipadatkan semula untuk dipadankan dengan tandatangan kelas induk menulis semula. Tetapi dengan berbuat demikian, semua syarat lain yang dinyatakan oleh LSP juga harus dipenuhi. Singkatnya, ini bermakna kaedah penulisan semula harus dilakukan dengan berhati -hati dan hanya boleh dilakukan untuk alasan yang sangat kuat. Dalam banyak kes penggunaan, dengan mengandaikan bahawa antara muka tidak boleh digunakan, lebih baik untuk membuat subclass yang hanya meluas (bukannya mengatasi) fungsi kelas asasnya. Dalam kes penyesuai PDO NEO, pendekatan ini akan berfungsi dengan sempurna dan tidak akan memecahkan kod klien di mana -mana peringkat. Seperti yang saya katakan, terdapat penyelesaian yang lebih efisien - tetapi lebih radikal - yang mengambil kesempatan untuk melaksanakan antara muka. Walaupun penyesuai PDO terdahulu dicipta melalui warisan dan tidak dapat dinafikan melanggar ajaran LSP, kelemahan sebenarnya datang dari cara kelas Agen Mapper pada asalnya direka. Malah, ia bergantung kepada pelaksanaan penyesuai pangkalan data konkrit dari atas ke bawah, dan bukannya pada kontrak yang ditetapkan antara muka. Dan kuasa OO yang besar telah dikatakan sejak zaman purba, ini selalu menjadi perkara yang buruk. Jadi, bagaimanakah penyelesaian di atas dilaksanakan?
Atas ialah kandungan terperinci Prinsip penggantian Liskov. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!