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

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

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

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


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

Новые заметки:

Про что мы забываем когда делаем оценку задачи по времени

Список вопросов для собеседования разработчика по телефону

Symfony2 авторизация без Doctrine2 для чайника

Phpstorm7 LiveEdit

Жесткий хабр или не хабр, тогда кто?

Яндекс.Деньги мошенничество

Как узнать какие страницы в поиске яндекса или это секрет

Последние комменты:

Yapro CMS:

Здравствуйте, Гость | Войти | Регистрация | Карта сайта | RSS ленты | Ошибка в тексте? Выделите её мышкой и нажмите: Ctrl + Enter

youtube.com/watch?v=7hFivbgIEqk

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

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