Рейтинг@Mail.ru
 
Наследование

Ну здесь все проще, сам термин уже содержит объяснение этого явления

Допустим мне по наследству от бабушки достался домик в деревне. Повезло.
Я могу просто поехать и попить молочка, а могу привезти с собой ящик пива и мангал. И устроить пикник и вечеринку. А в следующий раз мне писпичит привезти качели, деревянную лошадку, надувной басеин и сделать пионер-лагерь для своих детей и детей своих знакомых. А еще можно привезти... да много чего можно, был бы домик в деревне.

Так вот в программировании этот домик - базовый, родительский класс. Он будет неизменным, если конечно мы не спалим его, испив белого столового вина №21. А то, что мы имеем в данный момент, добавив к нему функционала - производные, дочерние классы.
Мы не строим каждый раз дом, что бы было где переночевать, мы просто добавляем к нему то, чего не хватает для приятного времяприпровождения

Рассмотрим это применительно к скриптам. Прямо как начали.
Вот домик:
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
<?php

/* 
* Class Small_house 
* @base 
*/   
class Small_house 

   static 
$house    'Домик'
   public 
$products = array( 
                             
=> 'Молоко'
                                  
'Сметана'
                                  
'Творог' 
                           
);    

   public function 
goFazenda($eat
   { 
       
$rest self::$house .' + '.$this->tomilkCow($eat);  
       return 
$rest
   }  
    
   public function 
tomilkCow($eat
   { 
       return 
$this->products[$eat]; 
   }    

/////////////////////////////////////////////////////
$rest = new Small_house();  
echo 
$rest -> goFazenda(1);

Можно спокойно поехать и попить молочка.

А можно прихватить детей и устроить им праздник:
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
<?php

/* 
* Class Small_house 
* @base 
*/   
class Small_house 

   static 
$house    'Домик'
   public 
$products = array( 
                             
=> 'Молоко'
                                  
'Сметана'
                                  
'Творог' 
                           
);    

   public function 
goFazenda($eat
   { 
       
$rest self::$house .' + '.$this->tomilkCow($eat);  
       return 
$rest
   }  
    
   public function 
tomilkCow($eat
   { 
       return 
$this->products[$eat]; 
   }    


/* 
* Class Kinder_garten 
* @extends Small_house 
*/ 
class Kinder_garten extends Small_house 


   public 
$toys = array( 
                             
=> 'Качеля'
                                  
'Лошадка'
                                  
'Басеин' 
                           
); 
                            
   public function 
restKinder($eat
   { 
       
$rest parent::goFazenda($eat) .' + 'implode(', '$this->toys); 
       return 
$rest
   }      


/////////////////////////////////////////////////////
$rest = new Kinder_garten(); 
echo 
$rest -> restKinder(2);


Вот заметьте, нет в новом классе никакой коровы, а сметана есть. А ведь мы не вызывали базовый класс. Почему так?
Потому что мы просто добавили к нашему пикнику игрушек, а корова и домик уже были в базовом классе. Нам совсем не обязательно каждый раз строить дом и разводить крупно-рогатый скот, раз у нас уже это все есть. Достаточно написать волшебное слово extends и имя класса, откуда мы хотим это все получить.
Обратиться к методу базового класса можно ключевым словом parent , то есть родительский.

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

Ну а раз дети резвятся, можно и немного нам расслабиться, если добавить к этим двум классам еще один:
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
<?php

/* 
* Class Crazy_party 
* @extends Kinder_garten 
*/ 
class Crazy_party extends Kinder_garten 


   public    
$attribute   ''
   public    
$beef        'сырой шашлык'
   public    
$beer        'пиво';  
   
   public function 
__construct($attribute false
   { 
       
$this->attribute $attribute
   }    
                                                      
   public function 
prepareKebab() 
   { 
       if(!empty(
$this->attribute)) 
       { 
           
$skewer explode(' '$this->beef); 
           return 
$skewer[1]; 
       } 
       else 
       { 
           return 
$beef
       } 
   }  
         
   public function 
drinkBeer() 
   { 
       return 
$this->beer
   } 

/////////////////////////////////////////////////////     
     
    
$rest = new Crazy_party('Мангал'); 
    echo 
$rest -> restKinder(1), '<br>'
    echo 
$rest -> prepareKebab(), '<br>'
    echo 
$rest -> beer
   


Этот класс является наследником наследника, а значит может работать с содержимым обоих классов. Поглядывать за детьми и готовить шашлык.

Вот тут нас подстерегает подвох. Пока мы разводим мангал, дети могут невзначай выпить наше непосильным трудом нажитое пиво.
Этого допустить, сами понимаете, никак нельзя. А по сему спрячем мы его в погреб от глаз подальше (за одно и охладится):
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
<?php

/* 
* Class Crazy_party 
* @extends Kinder_garten 
*/ 
class Crazy_party extends Kinder_garten 


   public    
$attribute   ''
   public    
$beef        'сырой шашлык'
   protected 
$beer        'пиво';  
   
   public function 
__construct($attribute ''
   { 
       
$this->attribute $attribute
   }    
                                                      
   public function 
prepareKebab() 
   { 
       if(!empty(
$this->attribute)) 
       { 
           
$skewer explode(' '$this->beef); 
           return 
$skewer[1]; 
       } 
       else 
       { 
           return 
$beef
       } 
   }  
         
   protected function 
drinkBeer() 
   { 
       return 
$this->beer
   } 

/////////////////////////////////////////////////////     
     
    
$rest = new Crazy_party('Мангал'); 
    echo 
$rest -> restKinder(1), '<br>'
    echo 
$rest -> prepareKebab(), '<br>'
    echo 
$rest -> drinkBeer();  
   


Что собственно изменилось. Изменился уровень доступа к пиву. Если сейчас запустить скрипт, пива нам не увидеть. Мы можем следить за детьми, угостить их шашлыком, а вот пива нет. Потому что protected - значит "защищенный"

А как же теперь вечеринка... Доступ к переменным и методам класса, которые имеют статус protected может быть осуществлен только из самого класса или его наследников. А не снаружи. Для наглядности сделаем такой класс:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

/* 
* Class Cold_cellar 
* @extends Crazy_party 
*/ 
class Cold_cellar extends Crazy_party 

   public function 
drinkBeer() 
   { 
      return 
'Ураа, 'parent::drinkBeer() .'!' 
   } 



///////////////////////////////////////////////////// 
    
$rest = new Crazy_party('Мангал'); 
    echo 
$rest -> restKinder(1), '<br>'
    echo 
$rest -> prepareKebab(), '<br>'
     
    
$beer = new Cold_cellar(); 
    echo 
$beer -> drinkBeer();


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

Наследование довольно удобная вещь. Не нужно переписывать код, который уже где то написан.
Но. Всегда есть но. Представьте себе эти классы, разложенные по разным файлам. Вот у нас допустим забарахлила выдача пива. То ли мы его забыли дома, то ли мыши выпили... Вобщем его нет. Что бы найти причину, мы ищем класс-родитель. А он оказывается наследник еще одного. И так далее. И вот, рспаковав десяток файлов, мы находим первоисточник.
Теперь нужно в голове представить всю картину, весь процесс прохождения этого напитка от ларька до желудка. Потому что цельной картины нет - все по файлам разбросано.

Бытует мнение, что ООП в этом плане удобно. Да. Для разработки удобно, сокращает несколько секунд на копипасте.
Но в программировании, как в литературе. Писатель один, а читателей много. То есть в разработке экономится пара минут, а вот в дальнейшем обслуживании (которое длится годами) - сущий ад. Понять логику отдельных разработчиков в принципе невозможно. Когда все приложение опутано веревками наследований, о прозрачности кода говорить вообще не приходится.

По этому будьте осторожны и взаимовежливы. Не увлекайтесь этим, а коль приспичит - снабжайте подробными комментариями.

Не пишите код так, как пишут инструкции к китайским изделиям:

ОПАСНЫЙ!
этот  ток ударить изделие огонь сгорел дом весь.
вода сырая нет пить имеет рвота понос.
рады вас пользоваться наш изделие
спасибо пожалуйста.


Пойди догадайся, что это чайник.

А нас ждет еще одна непролазная дебря - полиморфизм.