От автора: формируя структуру будущего проекта, редко удается описать логику одним единственным классом. Как правило, создается целая иерархия из различных классов, каждый из которых отвечает за функционал отдельного элемента будущего приложения. При этом для обеспечения большей гибкости и универсальности, как привило в основе логической структуры, располагаются классы которые, задают основной функционал и являются родительскими для всех последующих. Поэтому в данной статье мы с Вами рассмотрим такое понятие как наследование в ООП PHP.
Вообще есть три основных, главнейших принципа ООП на PHP — наследование, инкапсуляция, полиморфизм которые, по сути, определяют всю суть данного подхода, и как Вы поняли первый из них, мы рассматриваем сегодня, а об остальных поговорим в следующих статьях.
Итак, наследование в объектно-ориентированном программировании на PHP – это специальный механизм, благодаря которому несколько классов формируются из одного базового класса. При этом базовый класс называют родительским, а все производные от него – дочерними, или подклассами. В результате этого дочерние классы получают доступ к свойствам и методам родительского, что очень удобно, если необходимо вынести некий общий для некоторых классов функционал. Кроме того подклассы, конечно же могут содержать свои собственные методы и свойства и в этом случае, можно говорить, что они расширяют родительский класс.
vТеперь давайте рассмотрим следующий простейший пример. Предположим, что необходимо реализовать небольшое приложение со следующими разделами: блог, товары, пользователи (при этом раздел пользователи, должен только вывести на экран список конкретных пользователей). Таким образом, у нас есть три отдельные сущности, а значит для каждой из них нужно сформировать класс, в структуре которого будут описаны методы, по выборке необходимой информации и отображения ее на экран в соответствующем виде. Для отображения на экран может использоваться шаблонизатор, а для хранения информации – сервер базы данных MySQL.
Поэтому давайте посмотрим на возможную, упрощенную структуру одного из классов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?php class User { public $header; public $footer; public $content; public $db; public function __construct() { $this->db = new mysqli('localhost','root','','my_db'); $this->footer = "Footer Blog"; $this->header = "Header Blog"; } public function getHeader() { return $this->header; } public function getFooter() { return $this->footer; } public function render_body() { $statti = $this->get_content(); $str = ''; foreach($statti as $item) { $str .= "<div>"; $str .= '<h3>'.$item['title'].'</h3>'; $str .= '<p>'.$item['text']."</p>"; $str .= "</div>"; } return $str; } public function get_content() { $query = "SELECT * FROM `users` WHERE active == '1'"; $this->content = $this->db->query($query)->fetch_all(MYSQLI_ASSOC); return $this->content; } public function show() { return $this->getHeader().$this->render_body().$this->getFooter(); } } $obj = new Blog(); echo $obj->show(); |
Хотел бы сразу же, отметить, что класс очень и очень простой, в нем не предусмотрена гибкость для дальнейшего использования и расширения, а также не совсем корректно описан код, в плане использования вывода информации на экран. Потому как все что касается дизайна, необходимо выносить отдельно, в файлы шаблоны, которые содержат минимум логики. Но сейчас, задача состоит в том, что бы понять суть наследования, а значит для этого данный пример вполне подойдет.
Смотрите, описанный класс Blog, необходим для формирования структуры страницы отображения статей блога. В методе конструкторе, осуществляется соединение с сервером базы данных MySQL, потому как именно там располагается сохраненная информация по материалам. Методы getHeader() и getFooter(), возвращают содержимое шапки сайта и его футера соответственно. Основное содержимое страницы, формирует метод get_content() и, по сути, в нем мы видим выполнение простейшего SQL запроса.
В качестве шаблонизатора, выступает метод render_body(), хотя, это очень громкое его название, но все же. И, наконец, метод show(), собирает все, воедино, и возвращает для отображения на экран. Таким образом, для отображения информации на экран, достаточно создать объект вышеуказанного класса и отобразить на экран результат работы методы show().
Казалось бы, все очень просто, но нам ведь нужно, сформировать еще две аналогичные страницы и по сути код их классов, будет примерно такой же, за исключением метода get_content(), так как потребуется совсем другой SQL запрос, а также может, отличаться содержимое шапки и футера.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?php class User { public $header; public $footer; public $content; public $db; public function __construct() { $this->db = new mysqli('localhost','root','','my_db'); $this->footer = "Footer Users"; $this->header = "Header Users"; } public function getHeader() { return $this->header; } public function getFooter() { return $this->footer; } public function render_body() { $statti = $this->get_content(); $str = ''; foreach($statti as $item) { $str .= "<div>"; $str .= '<h3>'.$item['title'].'</h3>'; $str .= '<p>'.$item['text']."</p>"; $str .= "</div>"; } return $str; } public function get_content() { $query = "SELECT * FROM `users` WHERE active == '1'"; $this->content = $this->db->query($query)->fetch_all(MYSQLI_ASSOC); return $this->content; } public function show() { return $this->getHeader().$this->render_body().$this->getFooter(); } } $obj = new Blog(); echo $obj->show(); |
Как Вы видите, мы практически продублировали предыдущий класс, что, конечно же, не совсем правильно, особенно если нам нужен еще один похожий раздел.
Поэтому, весь общий функционал мы можем вынести в родительский класс, а в дочерних, наследуемых подклассах – описать только уникальные действия для конкретного раздела.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
<?php class Page { public function __construct() { $this->db = new mysqli('localhost','root','','my_db'); } public function getHeader() { return $this->header; } public function getFooter() { return $this->footer; } public function render_body() { $statti = $this->get_content(); $str = ''; foreach($statti as $item) { $str .= "<div>"; $str .= '<h3>'.$item['title'].'</h3>'; $str .= '<p>'.$item['text']."</p>"; $str .= "</div>"; } return $str; } public function show() { return $this->getHeader().$this->render_body().$this->getFooter(); } } class Blog extends Page { public function __construct() { parent::__construct(); $this->header = "Header Blog"; $this->footer = "Footer Blog"; } public function get_content() { $query = "SELECT * FROM `statti`"; $this->content = $this->db->query($query)->fetch_all(MYSQLI_ASSOC); return $this->content; } } class User extends Page { public function __construct() { parent::__construct(); $this->header = "Header User"; $this->footer = "Footer User"; } public function get_content() { $query = "SELECT * FROM `user` WHERE active = '1'"; $this->content = $this->db->query($query)->fetch_all(MYSQLI_ASSOC); return $this->content; } } $obj = new Blog(); echo $obj->show(); |
В примере выше, родительский класс – это класс Page, в который вынесен абсолютно весь общий функционал – подключение к базе данных, формирование шапки и футера сайта, метод шаблонизатора и метод show(). Соответственно, для создания дочернего класса, используется специальное слово extends, при объявлении класса. В нашем случае классы Blog и User, наследуют функционал родительского класса Page, то есть расширяют его. При этом они получают доступ к свойствам и методам базового класса. А значит, в их структуре достаточно описать только те методы, которые уникальны для конкретной сущности.
Более того, в дочерних классах, мы вправе переопределять методы, родительского класса, то есть создавать методы с аналогичным именем, но абсолютно другой реализацией. В качестве примера, мы видим переопределенный метод конструктора, в котором определяются значения свойств $header и $footer. При этом если метод переопределяется то, по сути, мы замещаем его код новым, а значит, если из объекта обратиться к данному методу, именно он будет вызван на исполнение. При этом очень часто, переопределяя код метода родительского класса, необходимо обращаться к этому же методу, но описанном в базовом классе. Что собственно Вы и видите в примере выше, в методе конструкторе. Для обращения к методу родительского класса, необходимо использовать зарезервированное слово parent. При этом, обращаясь к конструктору базового класса, мы выполняем подключение к базе данных, а после этого определяем значения свойств header и footer.
Таким образом, в объектно-ориентированном программировании наследование в PHP, характеризуется переопределением методов базового родительского класса.
Вот и все о чем я хотел сказать Вам в данной статье, как Вы видите, наследование классов очень удобно использовать при построении логики будущего приложения, так как благодаря ему мы можем сформировать полноценную иерархию классов. Более подробно текущая тема рассмотрена в курсе Курс по объектно-ориентированному программированию (ООП PHP).
Всего Вам доброго и удачного кодирования!!!