Инкапсуляция в объектно-ориентированном программировании на PHP

Инкапсуляция в объектно-ориентированном программировании на PHP

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

Итак, хотел бы напомнить, что элементы класса, могут быть объявлены, как:

public – открытые, или общедоступные;

protected – защищенные;

private – закрытые.

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее

Доступ к общедоступным свойствам или методам открыт из абсолютно любого контекста. То есть, создав объект интересующего класса, Вы всегда можете считать или изменить значение свойств, объявленный как public, а так же обратиться к методам, у которых определен данный спецификатор доступа.

<?php

class Page {
 public $title = 'Index Page';
}

$index = new Page();
echo $index->title;

По большому счету мы с Вами это уже рассматривали и не однократно использовали на практике, но повторение, как Вы знаете, ни когда не бывает лишним.

К защищенным элементам класса доступ извне, то есть из объекта, получить нельзя. Разрешается обращаться к указанным свойствам или методам из класса, в котором они определены, либо из его подклассов.

<?php


class Page {
 protected $title = 'Index Page';

 public  function getTitle()  {
  return $this->title;
 }
}

$index = new Page();
//приведет к ошибке
echo $index->title;

Таким образом, если мы в предыдущем примере, объявим свойство $title, используя спецификатор доступа protected — попытка обращения к нему, через объект, незамедлительно приведет к ошибке. Но при этом, мы знаем, что можно обращаться к подобному свойству, из класса, в котором оно определено, а значит, никто не запрещает определить открытый метод, который будет возвращать значение интересующего свойства.

<?php

class Page {
 protected $title = 'Index Page';

 public  function getTitle()  {
  return $this->title;
 }
 
}

$index = new Page();
echo $index->getTitle();

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

<?php

class Page {
 protected $title = 'Index Page';

 public  function getTitle()  {
  return $this->title;
 }
 
 public  function setTitle($title)  {
  $this->title = $title;
 }
 
}

$index = new Page();
$index->setTitle("New String");

echo $index->getTitle(); 

Защищенные свойства и методы, так же доступны и в классах наследниках.

class Page {
 protected $title = 'Index Page';
 
}

class IndexPage extends Page {
 public  function getTitle()  {
  return $this->title;
 }
 
 public  function setTitle($title)  {
  $this->title = $title;
 }
} 

$index = new Page();
$index->setTitle("New String");

echo $index->getTitle();

При этом к закрытым свойствам или методам можно получить доступ, только из того класса в котором они определены и не более. Таким образом, если в последнем примере, в родительском классе объявить свойство $title, со спецификатором доступа private – интерпретатор PHP вернет ошибку, так как, повторюсь, из дочернего класса нельзя обращаться к закрытым свойствам.

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее

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

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


class Tovar {
 public $nalog;
public $price;
 
 public function setNalog($nalog) {
  $this->nalog = $nalog;
 }
 
 public function getPriceTovar() {
  return $this->price + $this->nalog;
 }
}

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

$computer = new Tovar();
$computer->setNalog(100);

echo $computer->getPriceTovar();

Как Вы видите, в принципе все очень просто, есть цена, и есть метод, который ее формирует. Но есть небольшая проблема, которая заключается в том, что можно обратиться напрямую к свойству $price, в том случае если оно объявлено как открытое. И в этом случае, налог не будет учитываться для формирования окончательной цены, а значит, приложение будет работать не корректно. Что бы избежать этого, необходимо объявить свойство $price, со спецификатором доступа private, тем самым доступ к свойству, будет разрешен, только из метода getPriceTovar().

Но, в тоже время, уровень видимости private, так же запрещает доступ к свойству из дочерних классов, что приводит к тому, что мы не сможем создать подкласс, и переопределить метод getPriceTovar(), для несколько иной манипуляции над свойством $price. К примеру, если нужно для некоторой группы товаров, вообще не использовать налог при формировании цены, то мы могли бы переопределить метод getPriceTovar():

class Opt extends Tovar {
 public function getPriceTovar() {
  return $this->price;
 }
}

Но данный код приведет к ошибке, потому как свойство $price, закрыто для всех дочерних классов.

А значит, объявляя данное свойство в родительском классе, более правильно, использовать спецификатор доступа protected и тем самым предоставить доступ к нему дочерним классам.

Из этого вытекает небольшая рекомендация по проектированию структуры класса. Сначала определите все свойства и методы как закрытые, а далее по мере написания кода и необходимости ослабляйте ограничения. Лучше лишний раз закрыть элемент класса, чем ошибочно предоставить больший уровень видимости, чем это необходимо.

Теперь мы с Вами плавно подошли к последнему ключевому понятию, под названием — инкапсуляция.

В объектно-ориентированном программировании на PHP инкапсуляцией называют свойство классов скрывать собственную реализацию. И, по сути, в простейшем виде, мы с Вами только что инкапсулировали данные, используя спецификаторы доступа protected и private и тем самым закрывали, или лучше сказать скрывали свойство $price от клиентского кода. То есть, при этом задается некий интерфейс доступа к данным и по большому счету, зная его, нам абсолютно все равно как устроен конкретный класс, так как мы знаем какие методы в нашем распоряжении и как их необходимо использовать, тем самым предотвращается некорректная работа с данными класса.

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

На этом данная статья завершена. Всего Вам доброго и удачного кодирования!!!

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее
Самые свежие новости IT и веб-разработки на нашем Telegram-канале

Хотите изучить ООП PHP?

Прямо сейчас посмотрите курс по объектно-ориентированному программированию на PHP (ООП PHP)!

Смотреть курс

Метки:

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

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree