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

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

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

Класс, который получается в результате наследования от другого, называется подклассом. Эту связь обычно описывают с помощью терминов «родительский» и «дочерний». Дочерний класс происходит от родительского и наследует его характеристики: свойства и методы. Обычно в подклассе к функциональности родительского класса (который также называют суперклассом) добавляются новые функциональные возможности.

Чтобы создать подкласс, необходимо использовать в объявлении класса ключевое слово extends, и после него указать имя класса, от которого выполняется наследование:

<?php
  
  class Cat {
    public $age;
	
	function __construct($age) {
	  $this->age = $age;
	}
	
	function add_age () {
	  $this->age++;
	}
  
  }
  
  // объявляем наследуемый класс
  class my_Cat extends Cat {
    // определяем собственный метод подкласса
    function sleep() {
	  echo '<br>Zzzzz...';
	}
  }

  $kitty = new my_Cat(10);
  
  // вызываем наследуемый метод
  $kitty->add_age();
  
  // считываем значение наследуемого свойства
  echo $kitty->age;
  
  // вызываем собственный метод подкласса
  $kitty->sleep();
  
?>

Подкласс наследует доступ ко всем методам и свойствам родительского класса, так как они имеют тип public. Это означает, что для экземпляров класса my_Cat мы можем вызывать метод add_age() и обращаться к свойству $age не смотря на то, что они определены в классе cat. Также в приведенном примере подкласс не имеет своего конструктора. Если в подклассе не объявлен свой конструктор, то при создании экземпляров подкласса будет автоматически вызываться конструктор суперкласса.

Обратите внимание на то, что в подклассах могут переопределяться свойства и методы. Определяя подкласс, мы гарантируем, что его экземпляр определяется характеристиками сначала дочернего, а затем родительского класса. Чтобы лучше это понять рассмотрим пример:

<?php
  
  class Cat {
	public $age = 5;
	
	function foo() {
	  echo "$this->age";
	}
  }
  
  class my_Cat extends Cat {
    public $age = 10;
  }
  
  $kitty = new my_Cat;
  
  $kitty->foo();
  
?>

При вызове $kitty->foo() интерпретатор PHP не может найти такой метод в классе my_Cat, поэтому используется реализация этого метода заданная в классе Cat. Однако в подклассе определено собственное свойство $age, поэтому при обращении к нему в методе $kitty->foo(), интерпретатор PHP находит это свойство в классе my_Cat и использует его.

Так как мы уже рассмотрели тему про указание типа аргументов, осталось сказать о том, что если в качестве типа указан родительский класс, то все потомки для метода будут так же доступны для использования, посмотрите на следующий пример:

<?php
  
  class Cat {
    function foo(Cat $obj) {}
  }
   
  class my_Cat extends Cat {}
   
  $kitty = new Cat;
  
  // передаем методу экземпляр класса my_Cat  
  $kitty->foo( new my_Cat );
  
?>

Мы можем обращаться с экземпляром класса my_Cat так, как будто это объект типа Cat, т.е. мы можем передать объект типа my_Cat методу foo() класса Cat, и все будет работать, как надо.

Оператор parent

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

Чтобы вызвать нужный метод из родительского класса, вам понадобится обратиться к самому этому классу через дескриптор. Для этой цели в PHP предусмотрено ключевое слово parent. Оператор parent позволяет подклассам обращаться к методам (и конструкторам) родительского класса и дополнять их существующую функциональность. Чтобы обратиться к методу в контексте класса, используются символы "::" (два двоеточия). Синтаксис оператора parent:

parent::метод_родительского_класа

Эта конструкция вызовет метод, определенный в суперклассе. Вслед за таким вызовом можно поместить свой программный код, который добавит новую функциональность:

<?php
  
  class book {
    public $title;
	public $price;
	
	function __construct($title, $price) {
	  $this->title = $title;
	  $this->price = $price;
	}
  }
  
  class new_book extends book {
    public $pages;
	
	function __construct($title, $price, $pages) {
	  // вызываем метод-конструктор родительского класса
	  parent::__construct($title, $price);
	  
	  // инициализируем свойство определенное в подклассе
	  $this->pages = $pages;
	}
  }
  
  $obj = new new_book('азбука', 35, 500);
  
  echo "Книга: $obj->title<br>
        Цена: $obj->price<br>
		Страниц: $obj->pages";
  
?>

Когда в дочернем классе определяется свой конструктор, PHP не вызывает конструктор родительского класса автоматически. Это необходимо сделать вручную в конструкторе подкласса. Подкласс сначала в своем конструкторе вызывает конструктор своего родительского класса, передавая нужные аргументы для инициализации, исполняет его, а затем выполняется код, который реализует дополнительную функциональность, в данном случае инициализирует свойство подкласса.

Ключевое слово parent можно использовать не только в конструкторах, но и в любом другом методе, функциональность которого вы хотите расширить, достигнуть этого можно, вызвав метод родительского класса:

<?php
  
  class Cat {
    public $name = "Арни";
	
    function getstr() {
	  $str = "Имя кота: {$this->name}.";
	  return $str;
	}
  }
  
  class my_Cat extends Cat {
    public $age = 5;
	
	function getstr() {
	  $str = parent::getstr();
	  
	  $str .= "<br>Возраст: {$this->age} лет.";
	  return $str;
	}
  }
  
  $obj = new my_Cat;
  echo $obj->getstr();
  
?>

Здесь сначала вызывается метод getstr() из суперкласса, значение которого присваивается переменной, а после этого выполняется остальной код определенный в методе подкласса.

Теперь, когда мы познакомились с основами наследования, можно, наконец, рассмотреть вопрос видимости свойств и методов.

public, protected и private: управление доступом

До этого момента мы явно объявляли все свойства как public (общедоступные). И такой тип доступа задан по умолчанию для всех методов.

Элементы класса можно объявлять как public (общедоступные), protected (защищенные) и private (закрытые). Рассмотрим разницу между ними:

public - открытый доступ:

<?php
  
  class human {
    public $age = 5;
	public function say() {
      echo "<br>hello";
	}	
  }
  
  $obj = new human;
  
  // доступ из вызывающей программы
  echo "$obj->age";  // Допустимо
  $obj->say();       // Допустимо
  
?>

private - доступ только из методов класса:

<?php
  
  class human {
    private $age = 5;
	function say() {
	  // внутри класса доступ к закрытым данным есть
      echo "$this->age";
	}	
  }
  
  $obj = new human;
  
  // напрямую из вызывающей программы доступа к закрытым данным нет
  echo "$obj->age";  // Ошибка! доступ закрыт!
  
  // однако с помощью метода можно выводить закрытые данные
  $obj->say();       // Допустимо
  
?>

protected - защищенный доступ:

Модификатор protected с точки зрения вызывающей программы выглядит точно так же, как и private: он запрещает доступ к данным объекта извне. Однако в отличие от private он позволяет обращаться к данным не только из методов своего класса, но также и из методов подкласса.

Копирование материалов с данного сайта возможно только с разрешения администрации сайта
и при указании прямой активной ссылки на источник.
2011-2016 © puzzleweb.ru

Реклама на сайте | Обратная связь