PHP: полиморфизм, инкапсуляция и SOLID

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

Честно говоря, проще всего эти понятия расписаны тут, но если Вам этого мало, то читайте ниже.

Полиморфизм в PHP

Язык PHP поддерживает полиморфизм в том смысле, что позволяет использовать вместо экземпляров родительского класса экземпляры подкласса. Дело в том, что в каждом классе может присутствовать только один метод с определенным именем. Пример:

abstract class Publication {
 // определяем правило, что все публикации должны печататься, т.е. иметь метод do_print()
 abstract public function do_print();
}

class News extends Publication {
 // переопределяем абстрактный метод печати
 public function do_print() {
  echo '<h4>Новость</h4>';
  //...
 }
}
class Announcement extends Publication {
 // переопределяем абстрактный метод печати
 public function do_print() {
  echo '<h4>Объявление</h4>';
  //...
 }
}

//Наполняем массив публикаций объектами, производными от Publication
$publications[] = new News();
$publications[] = new Announcement();

foreach ($publications as $publication) {
 if ($publication instanceof Publication) { // Если мы работаем с наследниками Publication
  $publication->do_print(); // то мы можем смело выводить данные на печать
 }
 else {
  //исключение или обработка ошибки
 }
}

Главное здесь — последняя часть. Именно в ней заключается суть полиморфизма. Мы используем один и тот же код для объектов разных классов.

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

Инкапсуляция в PHP

Инкапсуляцию можно сравнить с работой автомобиля с точки зрения типичного водителя. Многие водители не разбираются в подробностях внутреннего устройства машины, но при этом управляют ею именно так, как было задумано. Пусть они не знают, как устроен двигатель, тормоз или рулевое управление, — существует специальный интерфейс, который автоматизирует и упрощает эти сложные операции. Сказанное также относится к инкапсуляции и ООП — многие подробности "внутреннего устройства" скрываются от пользователя, что позволяет ему сосредоточиться на решении конкретных задач. В ООП эта возможность обеспечивается классами, объектами и различными средствами выражения иерархических связей между ними.

В программном смысле этого слова, инкапсуляция - это скрытие переменных в классе от пользователя. Т.е. все переменные (свойства) класса Вы делаете скрытыми (private), а методы открытыми (public). Т.е. можно будет взаимодействовать со свойствами класса через методы.
Прелесть данного подхода в том, что в методах можна вставить код для проверки всяких ошибок, и потом о них не думать, когда вызывается метод.

Касательно SOLID

Хочется внести ясность в приципы Liskov substitution и Dependency inversion, т.к. теоретически сложно понять в чем их отличие, но я попробую.

abstract class Publication {
  final protected function getId(){ return $this->id; }
}

class News extends Publication {
 public function printId() {
  echo 'News ID: ' . $this->getId();
 }
}
class Article extends Publication {
 public function printId() {
  echo 'Article ID:' . $this->getId();
 }
}

Liskov substitution гласит: 

"Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа, не зная об этом." - означает, что если мы вызываем метод определенного класа, то этот класс должен быть замещаем (полиморфизм):

function printPublicationId(Publication $publication){
    $publication->printId();
}
printPublicationId(new News());
printPublicationId(new Article());

"Подклассы не могут замещать поведения базовых классов. Подтипы должны дополнять базовые типы." - означает, что мы должны расширять базовый класс (используя extend), но переопределять методы базового класса нельзя (инкапсуляция + поэтому мы написали final, см. выше).

Dependency inversion гласит:

"Зависимости внутри системы строятся на основе абстракций" - означает, что класс Publication должен быть абстрактным или интерфейсом, и затем именно его нужно передавать в функции (полиморфизм - см. выше вызовы printPublicationId).

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

Источник: 1 - 2

Оцени публикацию:
  • 6,28
Оценили человек: 6

Похожие статьи:

Справочники и учебники:


Предложения и пожелания:
Ваше имя:
Ваш E-mail:
Сколько будет Οдин + Τри
Главная
X

youtube.com/watch?v=7hFivbgIEqk

При полном или частичном использовании материалов данного сайта, ссылка на сайт "yapro.ru" обязательна как на источник информации.
Автоматический импорт материалов и информации с сайта запрещен.
Copyrights © 2007 - 2018 YaPro.Ru

Главная » Веб-мастеру » PHP »