Лабораторная работа ч.3 по объектно-ориентированному программированию на PHP
Это третья часть лабораторной работы по ООП. Первый две части можно найти тут: часть 1 и часть 2.
Сегодня мы продолжаем заниматься практической деятельностью по освоению объектно-ориентированного программирования. И давайте начнем наш сегодняшний урок с такого понятия, как полиморфизм или по-другому — наследование.
Итак, что же такое полиморфизм?
Это способность класса наследовать все свойства и все методы предыдущего класса. В этом случае предыдущий класс будет выступать в роли родителя, а класс, который от него (родителя) наследует будет выступать в роли наследника.
Например, у меня есть класс Car со свойством, которое называется «год выпуска» ($year) и методом, который выводит скорость автомобиля и называется он — function paintSpeed():
<?php
class Car{
//свойства
public $year = 2003;
//метод
function paintSpeed(){
echo "Скорость автомобиля = ".$this->speed;
}
}
?>
На основе этого класса, я могу создать класс, например, класс Opel, который будет иметь такое же свойство и такой же метод, как мой класс Car. Теперь класс Car является родителем для класса Opel.
Так как же создается наследование?
Класс наследник или наследование (полиморфизм) создается с помощью ключевого слова extends.
Давайте посмотрим на примере:
<?php
//это класс родитель
class Car{
//свойства
public $year = 2003;
//метод
function paintSpeed(){
//указываем методу, чью скорость мы хотим получить. Идет обращение из метода к свойству
echo "Скорость автомобиля = ".$this->speed;
}
}
//это класс наследник, который имеет свойство $year и метод paintSpeed()
class Opel extends Car{
//свойство
public $model;
}
?>
Еще раз:
Когда мы создаем класс наследник, используя ключевое слово extends, то он автоматически наследует все свойства и методы класса родителя. В самом классе-наследнике мы не увидим этих свойств и методов, однако они там есть и к ним можно будет обращаться. Как именно это делать, я покажу далее.
Однако и сам класс наследник наряду со свойствами и методами класса родителя может иметь так же и свои свойства и методы.
Важно отметить, что после ключевого слова extends обязательно должно идти название класса, от которого мы собственно все и наследуем.
Теперь давайте посмотрим, как мы можем обращаться из класса наследника к его собственным свойствам и методам, так и к унаследованным:
<?php
//это класс родитель
class Car{
//свойства
public $year = 2003;
//метод
function paintSpeed(){
//указываем методу, чью скорость мы хотим получить. Идет обращение из метода к свойству
echo "Скорость автомобиля = ".$this->speed;
}
}
//это класс наследник, который имеет свойство $year и метод paintSpeed()
class Opel extends Car{
//свойство
public $model;
}
$myCar = new Opel();
//обращение к свойству класса родителя
$myCar->$year;
//обращение к собственному свойству
$myCar->$model;
?>
Соответственно из класса Opel мы тоже можем создать класс наследник.
Теперь давайте вернемся к нашей лабораторной работе.
Задание у нас будет следующее:
- Описать класс SuperUsers унаследованный от класса Users;
- В классе SuperUsers описать свойство character и создать объект, экземпляр класса SuperUsers;
- Задать значение свойству character = «admin»;
- Вызвать метод getInfo() для созданного объекта;
- Отдельно от метода getInfo() вывести значение свойства character;
Вот что у нас должно было получиться:
<?php
class Users{
public $name;
public $login;
public $password;
//создание конструктора
function __construct($name, $login, $password){
$this->name = $name;
$this->login = $login;
$this->password = $password;
}
//создаем метод clone
function __clone(){
$this->name = "User";
$this->login = "User";
$this->password = "qwerty";
}
//создаем методод getInfo()
function getInfo(){
echo "<p>Name: ".$this->name."<br>";
echo "Login: ".$this->login."<br>";
echo "Password: ".$this->password."<br>";
}
}
$user1 = new Users("Vasya", "vas", "123");
//выводим метод getInfo()
$user1->getInfo();
$user2 = new Users("Petya", "pet", "321");
//выводим метод getInfo()
$user2->getInfo();
$user3 = new Users("Vova", "vov", "456");
//выводим метод getInfo()
$user3->getInfo();
//объект $user4 копия объекта $user3
$user4 = clone $user3;
$user4->getInfo();
//Создаем класс наследник от класса Users
class SuperUsers extends Users{
//создаем свойство character
public $character;
}
//создаем объект экземпляр класса SuperUsers
$user = new SuperUsers("SuperAdmin", "root", "admin1234");
//задаем значение свойству character = admin
$user->character = "admin";
//вызываем метод getInfo() для созданного объекта
$user->getInfo();
//выводим значение свойства character
echo $user->character;
?>
Запустив этот код вы увидите, что у нас появился новый пользователь SuperAdmin, который обладает такими же свойствами и методами, что и пользователи класса Users + он имеет собственное свойство-характеристику (character) — админ.
Друзья, обратите внимание, что когда мы только что создали объект класса SuperUsers, он также унаследовал и конструктор своего родителя Users. Конструктор родителя, как мы знаем может принимать три параметра ($name, $login, $password). А в классе наследнике у нас появляется четвертый параметр character, который мы прописали отдельно.
Вот тут мы с вами подходим к такому понятию, как перегрузка методов.
Что же это такое? Например, у нас есть класс родитель и класс наследник. В классе родителе описан метод getPrint() и в классе наследнике мы тоже описываем метод getPrint(), хотя он уже там есть, так как унаследован от класса родителя. Но описываем мы его немного с другими параметрами, которые нам нужны именно в классе наследнике. Так вот, при вызове метода из экземпляра класса будет вызван именно метод из класса наследника, то есть переписанный.
Знаю, немного запутанно получилось, поэтому давайте посмотрим на примере:
<?php
class Car{
//свойство
public $model = "Mazda";
//метод
function getPrint(){
echo $this->model;
}
}
//создаем класс наследник
class Infinity extends Car{
//свойство
public $country = "Japan";
//метод, который мы перегружаем, то есть переписываем его с нужными нам здесь параметрами
function getPrint(){
echo "Перегруженный метод getPrint()";
}
}
//создаем экземпляр класса Infinity
$myCar = new Infinity();
//вызываем метод getPrint()
$myCar->getPrint();//ВАЖНО! Будет вызван перегруженный метод из класса наследника Infinity
?>
Запустив этот код у нас выведется надпись — «Перегруженный метод getPrint()», а не слово «Mazda». Попробуйте в классе наследнике убрать перегруженный метод и вы увидите, что будет происходить обращение к обычному методу getPrint(), унаследованному от родителя и в этом случае выведется надпись «Mazda». Другими словами перегруженный метод у наследника как бы перекрывает родительский.
В связи с этим давайте выполним задание лабораторной работы. А именно:
- описать конструктор класса SuperUsers, который будет задавать начальные значения свойств;
- в классе SuperUsers описать метод getInfo(), который будет выводить значения этих свойств;
- создать заново объект класса SuperUsers и вызвать метод getInfo();
И вот что у вас должно получиться:
<?php
class Users{
public $name;
public $login;
public $password;
//создание конструктора
function __construct($name, $login, $password){
$this->name = $name;
$this->login = $login;
$this->password = $password;
}
//создаем метод clone
function __clone(){
$this->name = "User";
$this->login = "User";
$this->password = "qwerty";
}
//создаем методод getInfo()
function getInfo(){
echo "<p>Name: ".$this->name."<br>";
echo "Login: ".$this->login."<br>";
echo "Password: ".$this->password."<br>";
}
}
$user1 = new Users("Vasya", "vas", "123");
//выводим метод getInfo()
$user1->getInfo();
$user2 = new Users("Petya", "pet", "321");
//выводим метод getInfo()
$user2->getInfo();
$user3 = new Users("Vova", "vov", "456");
//выводим метод getInfo()
$user3->getInfo();
//объект $user4 копия объекта $user3
$user4 = clone $user3;
$user4->getInfo();
//Создаем класс наследник от класса Users
class SuperUsers extends Users{
//создаем свойство character
public $character;
//описываем конструктор для SuperUsers
function __construct($name, $login, $password, $character){
$this->name = $name;
$this->login = $login;
$this->password = $password;
$this->character = $character;
}
//перегружаем метод getInfo
function getInfo(){
echo "<p>Name: ".$this->name."<br>";
echo "Login: ".$this->login."<br>";
echo "Password: ".$this->password."<br>";
echo "Character: ".$this->character."<br>";
}
}
//создаем объект экземпляр класса SuperUsers
$user = new SuperUsers("SuperAdmin", "root", "admin1234", "admin");
//вызываем метод getInfo() для созданного объекта
$user->getInfo();
?>
Однако, если мы посмотрим на наш код, то мы можем сказать, что здесь что-то не так. Мы говорили о том, что вся прелесть наследования заключается в том, что мы все забираем у класса родителя, а тут нам пришлось все переписать практически заново. В итоге у нас произошло увеличение кода, что в идеале не есть хорошо. А если предположить, что у нас от класса SuperUsers будет наследоваться еще один класс SuperPuperUser, а от него еще какой нибудь, то количество строк кода будет возрастать до неимоверных пределов. Поэтому с этим надо что-то делать.
Допустим, мы в данном случае перегрузили родительский метод. Поэтому метод родителя нам уже не доступен. А что если я хочу иметь возможность обратиться и к родительскому методу и перегруженному?
Для этих целей у нас существует замечательная конструкция — parent.
Записывается она так — parent->двойное двоеточие->имя метода.
parent::имя метода
Эта конструкция позволяет обратиться к родительскому методу. Суть его работы заключается в том, что когда мы перегружаем родительский метод в классе наследнике, нам уже не надо еще раз описывать метод родителя. Мы просто в перегруженном методе обращаемся к методу родителя посредством конструкции parent, а если у нас есть дополнения к методу, то указываем их ниже этой конструкции:
<?php
//Создаем класс наследник от класса Users
class SuperUsers extends Users{
//создаем свойство character
public $character;
//описываем конструктор для SuperUsers
function __construct($name, $login, $password, $character){
//ОБРАЩАЕМСЯ К МЕТОДУ (КОНСТРУКТОРУ) РОДИТЕЛЯ ПОСРЕДСТВОМ PARENT
parent::__construct($name, $login, $password);
//+ у нас дополнительное свойство character, которое указываем ниже parent и не забываем также указать его в параметрах перегруженного метода
$this->character = $character;
}
//перегружаем метод getInfo
function getInfo(){
//то же самое - обращаемся к родительскому методу getInfo()
parent::getInfo();
//+ дополнительное свойство
echo "Character: ".$this->character."<br>";
}
}
//создаем объект экземпляр класса SuperUsers
$user = new SuperUsers("SuperAdmin", "root", "admin1234", "admin");
//вызываем метод getInfo() для созданного объекта
$user->getInfo();
?>
Вот и все. В результате у нас ничего не измениться, за исключением того, что мы немного сократили количество кода.
|