ООП в php - Наследование

 

Доброго времени суток. Спасибо что читаете данный блог Улыбаюсь, даже если он так не часто обновляется. Спасибо тем кто все еще пишет комментарии на блоге, и присылает мне письма с вопросами. На те вопросы на которые я смог ответить, я ответил, на остальные же прошу прощения Хмурюсь

О чем сегодня поговорим? А поговорим мы о наследование в ООП. Это пожалуй самое главное, без чего объектно — ориентированное программирование почти ничем не отличается от процедурного.

 

В прошлой заметки рубрики «Я учусь» мы писали класс кружки. Пример может и не самый удачный, тем не менее не грузит мозг, как у некоторых авторов, которые пытались объяснить, что такое классы. Сейчас мы немного изменим наш класс. Для данного урока нужно отделить методы:

  • «Положить в кружку чай или кофе», метод set_drink()
  • «Налить в кружку воды», метод set_water()
  • «Положить сахар», метод set_sugar()

От метода «Помешать содержимое кружки» — interfere_with()

Для чего это нужно? Ну начну с того что сегодня я собираюсь в месте с Вами написать класс термоса. Как Вам известно термос это тоже некая емкость в которой можно хранить напитки. В термос так же можно налить воды, положить чай или кофе и насыпать сахар. В общем то термос, в плане нашего кода, ничем не отличается от нашей кружки. Можно было бы просто скопировать класс кружки, переназвать его и делов то Улыбаюсь

Но данный подход нам не интересен, поэтому вынесем общие методы в отдельный класс. Этот класс я назвал common_actions. Вот код класса:

class common_actions
{
    public $drink = '';// кофе или чай
    public $water = FALSE;// вода (TRUE вода налита; FALSE вода не налита)
    public $sugar = FALSE;// сахар (TRUE положили сахар; FALSE не положили сахар)
    
    // положить кофе или чай.. ну или еще что-нить =)
    function set_drink($name)
    {
        $this->drink = $name;
    }
    
    // налить воды
    function set_water()
    {
        $this->water = TRUE;
    }
    
    // положить сахар
    function set_sugar()
    {
        $this->sugar = TRUE;
    }
}

Вот как сейчас выглядит мой файл:

class common_actions
{
    public $drink = '';// кофе или чай
    public $water = FALSE;// вода (TRUE вода налита; FALSE вода не налита)
    public $sugar = FALSE;// сахар (TRUE положили сахар; FALSE не положили сахар)
    
    // положить кофе или чай.. ну или еще что-нить =)
    function set_drink($name)
    {
        $this->drink = $name;
    }
    
    // налить воды
    function set_water()
    {
        $this->water = TRUE;
    }
    
    // положить сахар
    function set_sugar()
    {
        $this->sugar = TRUE;
    }
}

class glass
{
    // мешать содержимое кружки ложкой
    function interfere_with()
    {
        if (empty($this->drink) AND $this->water == FALSE AND $this->sugar == FALSE)
            return "Дзынь-дзынь... кружка пуста, и я не знаю какого результата Вы ждете =(";
       
        if (!empty($this->drink) AND $this->water == FALSE AND $this->sugar == FALSE)
            return "Странный скрежет... К сожалению результата нет =(";

         if (!empty($this->drink) AND $this->water == TRUE AND $this->sugar == FALSE)
            return "Дзынь-дзынь... Ура! Вы получили НЕ сладкий ".$this->drink;   
    
        if (!empty($this->drink) AND $this->water == TRUE AND $this->sugar == TRUE)
            return "Дзынь-дзынь... Ура! Вы получили сладкий ".$this->drink;

        if (empty($this->drink) AND $this->water == TRUE AND $this->sugar == TRUE)
            return "Дзынь-дзынь... Ура! Вы получили cладкую воду";
        
        if (empty($this->drink) AND $this->water == FALSE AND $this->sugar == TRUE)
            return "Странный скрежет... К сожалению результата нет =(";
            
        if (empty($this->drink) AND $this->water == TRUE AND $this->sugar == FALSE)
            return "Дзынь-дзынь... В кружке просто вода";            
            
        if (!empty($this->drink) AND $this->water == FALSE AND $this->sugar == TRUE)
            return "Странный скрежет... К сожалению результата нет =(";
    }
}

$glass = new glass();

$glass->set_drink('кофе');// насыпим кофе
$glass->set_sugar();// насыпим сахар
$glass->set_water();// зальем водой

echo $glass->interfere_with();// помешаем

Если Вы его сейчас запустите, то ничего хорошего у Вас не получится, но Вы не расстраивайтесь Улыбаюсь, мы лишь привели код к нужному нам виду.

Во избежание всяких ошибок, я выкладываю данный файл. Скачать его можно вот тут

Пишем класс термоса

Если Вы взгляните сейчас на наш файл, а именно на класс glass, то увидите там лишь один метод, метод interfere_with(). Отсюда можно сделать вывод, что класс термоса должен иметь что-то подобное. Но как нам известно у термоса есть еще крышка, поэтому я предлагаю создать метод в классе термоса, который бы позволял открыть и закрыть крышку.

Давай приступим к созданию нового класса (Я пишу код в том же файле)

class thermos
{
    public $cover = FALSE;// крышка термоса закрыта (false) иои открыта (true)
    
    function action_cover()
    {
        if ($this->cover == FALSE)
            $this->cover = TRUE;
        else
            $this->cover = FALSE;
    }
    
    // мешать содержимое термоса
    function interfere_with()
    {
        // новое условие позволяющие определить открыта или закрыта крышка у термоса
        if ($this->cover == FALSE)
            return "Крышка закрыта, удивитеьлно что Вы сразу не заметили";
        
        if (empty($this->drink) AND $this->water == FALSE AND $this->sugar == FALSE)
            return "Дзынь-дзынь... термос пуст, и я не знаю какого результата Вы ждете =(";
       
        if (!empty($this->drink) AND $this->water == FALSE AND $this->sugar == FALSE)
            return "Странный скрежет... К сожалению результата нет =(";

         if (!empty($this->drink) AND $this->water == TRUE AND $this->sugar == FALSE)
            return "Дзынь-дзынь... Ура! Вы получили НЕ сладкий ".$this->drink;   
    
        if (!empty($this->drink) AND $this->water == TRUE AND $this->sugar == TRUE)
            return "Дзынь-дзынь... Ура! Вы получили сладкий ".$this->drink;

        if (empty($this->drink) AND $this->water == TRUE AND $this->sugar == TRUE)
            return "Дзынь-дзынь... Ура! Вы получили cладкую воду";
        
        if (empty($this->drink) AND $this->water == FALSE AND $this->sugar == TRUE)
            return "Странный скрежет... К сожалению результата нет =(";
            
        if (empty($this->drink) AND $this->water == TRUE AND $this->sugar == FALSE)
            return "Дзынь-дзынь... В термосе просто вода";            
            
        if (!empty($this->drink) AND $this->water == FALSE AND $this->sugar == TRUE)
            return "Странный скрежет... К сожалению результата нет =(";
    }
}

Класс я назвал thermos, Создал в нем новое свойство cover. Данное свойство будет определять открытия или закрытие крышки.

Метод action_cover() позволяет менять состояние крышки (т.е. метод меняет значение с true на false и обратно). В методе interfere_with() появилось новое условие, позволяющие определить открыта крышка или нет.

Ну что же, теперь у нас есть класс термоса, но работать он пока не будет, так как он еще не знает таких методов как:

  • set_drink()
  • set_water()
  • set_sugar()

Вот тут то как раз иприходит к нам на помощь чудо-штука под название наследование. В чем ее смысл?

Наследование

В нашем примере видно что есть три класса:

  1. common_actions — Данный класс содержит общие методы для других классов
  2. glass — Класс кружки
  3. thermos — Класс термоса

Нам известно, что два последних класса используют методы из первого класса и нам необходимо сделать так что бы первый класс стал родителем второго и третьего класса, то есть что бы два последних класса стали дочерними первого.

Проще говоря в ООП есть возможность использовать методы которые находятся в другом классе. Для этого необходимо указать родителя (тот класс из которого мы хотим взять методы). Делается это проще простого. После объявление имени класса, необходимо написать ключевое слово extends после чего необходимо написать имя класса родителя (класса из которого необходимо взять методы)

В коде это выглядит вот так:

class glass extends common_actions
{
...
}

class thermos extends common_actions
{
..
}

Теперь наши класс кружка и термос могут использовать методы которые лежат в класса common_actions

Давайте протестируем наши классы. Для этого в самом низу напишем вот этот код:

// завариваем напиток в кружке
$glass = new glass();

$glass->set_drink('кофе');// насыпим кофе
$glass->set_sugar();// насыпим сахар
$glass->set_water();// зальем водой

echo $glass->interfere_with();// помешаем

// завариваем напиток в термосе
$thermos = new thermos();

$thermos->action_cover();// откроем крышку термоса

$thermos->set_drink('чай');// насыпим кофе
$thermos->set_sugar();// насыпим сахар
$thermos->set_water();// зальем водой

echo "<br /><br />".$thermos->interfere_with();// помешаем

После запуска я получил вот такой результат:

 

результат

Заключение

Надеюсь смысл наследования Вам ясен. На практике (т.е. при построение той же CMS) наследование используется для того чтобы получить доступ к методам ядра, которое содержит в себе инструменты по работе с данными, базой данных и т.д

Прежде чем закончить данную статью, я выложу Вам готовый файл который сегодня получился у меня, Вам так будет проще разобраться в том что я написал Улыбаюсь. Файл можно скачать вот отсюда. Если у Вас есть какие либо вопросы, то задавайте, с удовольствием попытаюсь ответить Улыбаюсь

Всего Вам наилучшего, у меня все!

 

Возможно Вам будут интересны следующие заметки

Комментарии (21)

Ваше имя *
Сайт
Ваш E-mail *
Ваше сообщение *
 
simofon, 29 Июня 2013 г. 21:06 пишет:
Читатель
просто и ясно! пойду попью чайку ))) . Спасибо
Васян, 30 Июня 2013 г. 21:29 пишет:
Гость
Спасибо за статью, очень хорошо написано, как и предидущая. Знал что это, но не понимал зачем это, теперь все предельно ясно)
Joker, 10 Июля 2013 г. 05:38 пишет:
Гость
А можете ли реализовать для RSBlog, поиск? а то без него не как :(
Алексей, 10 Июля 2013 г. 10:28 пишет:
Автор
Я думаю лучше привязать поисковик от яндекса или гугла. Инструкций в интернете полно, так что сделать это не сложно
Ответ для пользователя: Joker
Joker, 11 Июля 2013 г. 08:17 пишет:
Гость
Извините но у меня в меню проблема :(
вставляю в menu.tpl.php:
<ul class="menu">
[_divmenu]
<li>
[_station]
<ul>
<li>
[_podmenu]
</li>
</ul>
</li>
[_divmenu]
</ul>
открываю на сайте и он отображает его криво и открываю исходный код страница а там вот:
<ul class="menu">

<li>
<a href="/about.html">Обо мне</a>
<ul>
<li>

<li>
<a href="/">Главная</a>
<ul>
<li>

</li>
</ul>
</li>
</ul>

</li>
</ul>
</li>
</ul>
и в чём может быть проблема? у меня создан 1 пункт и один подпункт для того чтобы показать всплывающее меню. помогите пожалуйста :)
Ответ для пользователя: Алексей
Joker, 11 Июля 2013 г. 10:49 пишет:
Гость
Помогите пожалуйста решить проблему а?
Ответ для пользователя: Алексей
Алексей, 11 Июля 2013 г. 11:30 пишет:
Автор
Не используйте списки, используйте дивы. Для того что бы была возможность использовать списки, нужно переделать модуль меню. Как его переделать, я сейчас не знаю (в код не смотрю)
Ответ для пользователя: Joker
Joker, 11 Июля 2013 г. 12:37 пишет:
Гость
Простите но мне дивы не устраивают. мне нужно конкретное меню
Ответ для пользователя: Алексей
Алексей, 11 Июля 2013 г. 15:15 пишет:
Автор
Боюсь, что с модулем меню, который есть сейчас, можно использовать только дивы
Ответ для пользователя: Joker
Joker, 11 Июля 2013 г. 15:19 пишет:
Гость
У вас же стоит боковое меню :( помогите мне реализовать масличко сливошное
Ответ для пользователя: Алексей
Алексей, 11 Июля 2013 г. 16:38 пишет:
Автор
У меня блог сейчас работает на RS-SITE, а не на RS-BLOG. На RS-BLOG нужно переделывать модуль меню, так как сейчас модуль сохраняет все то, что между [_divmenu] и [_divmenu], и копирует этот код для каждого пункта, в том числе и для подпунктов.

Вы какой версией RS-BLOG пользуетесь? Той, что по почте Вам прислали, или той, что собрали во время прохождения цикла статей "Создать блог с нуля"?
Ответ для пользователя: Joker
Алексей, 11 Июля 2013 г. 17:07 пишет:
Автор
У Вас есть три выхода:

1. Обернуть весь список в код-слова [_divmenu], т.е. приблизительно вот так:
[_divmenu]
<ul class="menu">
    <li>[_station][_podmenu]<li>
</ul>
[_divmenu]
В этом случае Вы получите для каждого пункта свою обвертку в тег <ul>. В общем то это НЕ самый хороший вариант.

2. Обернуть подменю в коде модуля menu.php. Файл находится в папке moduls. Найдите там вот эту строчку:
$edd_tamp = str_replace("[_podmenu]", $podmenu, $edd_tamp);
и измените вот так:
if ($podmenu != '')
    $podmenu = "<ul>".$podmenu."</ul>"
	
$edd_tamp = str_replace("[_podmenu]", $podmenu, $edd_tamp);
Код шаблона должен быть вот таким:
<ul class="menu">
[_divmenu]
    <li>[_station][_podmenu]<li>
[_divmenu]
</ul>
3. Все же использовать дивы вместо списка
Ответ для пользователя: Joker
dlegame, 08 Августа 2013 г. 07:02 пишет:
Читатель
Уважаемый Rio-Shaman! просветите пожалуйста как можно реализовать отображение в статьи и ленте новостей, чтобы показывало в какой опубликовано категории статья? если не было добавлена в какую категорию то отобразить: На главной
Алексей, 08 Августа 2013 г. 10:18 пишет:
Автор
Если я не ошибаюсь, то все пункты меню (категории) собраны в один массив. Что Вам мешает пролистать данный массив и найти все нужные данные для отображения?
Ответ для пользователя: dlegame
dlegame, 08 Августа 2013 г. 11:52 пишет:
Читатель
Да вы меня не поняли xD
с меню у меня все решено) и вот как сделать как у вас? скрин: http://rghost.ru/47972433/image.png
Ответ для пользователя: Алексей
Алексей, 08 Августа 2013 г. 12:06 пишет:
Автор
Я как раз про это и говорю. К заметкам привязан id каталога. Находим по id в массиве нужный пункт, после чего отыскиваем родителей данного пункта... Ну и на по следок остается собрать, из полученных кусочков информации, ссылку...
Ответ для пользователя: dlegame
dlegame, 08 Августа 2013 г. 13:04 пишет:
Читатель
Блин чувак спасибо) ща буду пробывать написать)
Ответ для пользователя: Алексей
dlegame, 05 Октября 2013 г. 08:24 пишет:
Читатель
Привет Алексей! тут проблемка одна появилась не знаю что уж и делать :(
короче помните вы мне помогли функцию BB-code помогли внедрить? и вот в этой функции при вставке url можно только например так:
[url=rio-shaman.ru]Блог RS[/url]
а как сделать чтобы можно было публиковать любую ссылку например так:
[url=http://rio-shaman.ru/ja-uchus/oop-v-php-nasledovanie/]Блог RS[/url]
ибо он такую не обрабатывает :( вот код:
	$text = preg_replace('/\[url\](?:http:\/\/)?([a-z0-9-.]+\.\w{2,4})\[\/url\]/', "<div id=\"link\"></div><a href=\"javascript://\" onclick=\"open_link('http://$1')\" rel=\"nofollow\">$1</a>", $text);
	$text = preg_replace('/\[url\s?=\s?([\'"]?)(?:http:\/\/)?([a-z0-9-.]+\.\w{2,4})\1\](.*?)\[\/url\]/', "<div id=\"link\"></div><a href=\"javascript://\" onclick=\"open_link('http://$2')\" rel=\"nofollow\">$3</a>", $text);
Алексей, 05 Октября 2013 г. 11:16 пишет:
Автор
В Ваших регулярных выражениях у ссылки нет символа '/'
Ответ для пользователя: dlegame
dlegame, 05 Октября 2013 г. 14:28 пишет:
Читатель
И куда нужно добавить чтобы в регулярном выражении обрабатывало ссылки любым видом?
Ответ для пользователя: Алексей
Алексей, 16 Октября 2013 г. 11:44 пишет:
Автор
Все забываю Вам отписать.
Вот регулярки которые должны работать с выше представленными примерами:
$text = preg_replace('/\[url\](?:http:\/\/)?([a-z0-9-_.]+\.\w{2,4}[a-z0-9-_.\/]*)\[\/url\]/', "<div id=\"link\"></div><a href=\"javascript://\" onclick=\"open_link('http://$1')\" rel=\"nofollow\">$1</a>", $text);
$text = preg_replace('/\[url=(?:http:\/\/)?([a-z0-9-_.]+\.\w{2,4}[a-z0-9-_.\/]*)\](.*?)\[\/url\]/', "<div id=\"link\"></div><a href=\"javascript://\" onclick=\"open_link('http://$1')\" rel=\"nofollow\">$2</a>", $text);
P.S. : Отыскивать ББ коды с помощью подобных регулярных выражений не правильно, и все это будет работать до пары до времени.
Ответ для пользователя: dlegame