Модификаторы доступа в ООП PHP. Геттеры и сеттеры

Модификаторы доступа
Геттеры и сеттеры



Область видимости: php.net


Модификаторы доступа (области видимости)

Геттеры и сеттеры



Модификаторы доступа




Область видимости свойства, метода или константы (PHP 7.1) может быть определена путем использования следующих ключевых слов в объявлении: public, protected или private.

- public (общедоступный) - свойство или метод доступны отовсюду (в классе, во всех классах-наследниках, из вне класса).

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

- private (закрытый) - свойства или методы доступны только в том классе, где они объявленны. В наследниках, из вне класса такое свойство или метод доступны не будут и использовать их не получиться.


Модификаторы (области видимости) предназначены для контроля нашего кода.


В классе Product (все файлы - из предыдущего урока "Наследование") создадим новые свойства:

$public , $protected, $private и в индексном файле распечатаем их - debug($book).

Попытаемся обратиться к каждому из свойств.

При попытке обратиться к свойствам $protected и $private из вне класса (index.php) - выводится ошибка.

При обращении к этим свойствам из класса Product - все они выводятся.

При обращении из дочернего класса BookProduct - свойство $private - не доступно.


Обращение к свойствам $public, $protected, $private из класса Product (где они были объявлены):


Файл Product.php


-- файл Product.php --

<?php
class Product
{
public $name; // наименование товара
public $price; // цена товара

// создадим новые свойства
public $public = 'PUBLIC';
protected $protected = 'PROTECTED';
private $private = 'PRIVATE';

public function __construct($name, $price)
{
$this -> name = $name;
$this -> price = $price;
// попытаемся обратиться к каждому из свойств внутри класса (все свойства доступны)
var_dump($this -> public);
var_dump($this -> protected);
var_dump($this -> private);
}
}
?>





Обращение к свойствам $public, $protected, $private из дочернего класса BookProduct:


Файл BookProduct.php


-- файл BookProduct.php --

<?php
class BookProduct extends Product
{
public $numPages;

public function __construct($name, $price, $numPages)
{
parent :: __construct($name, $price);
$this -> numPages = $numPages;

// попытаемся обратиться к каждому из свойств в дочернем классе
var_dump($this -> public);
var_dump($this -> protected);
//var_dump($this->private); // Неопределенное свойство (свойство не доступно)
}

//...
//...
//...
}
?>





Обращение к свойствам $public, $protected, $private из вне класса (index.php):


Файл index.php


-- файл index.php --

<?php
error_reporting(-1);
require_once 'classes/Product.php';
require_once 'classes/BookProduct.php'; // подключаем класс BookProduct
function debug($data)
{
echo '<pre>' . print_r($data, 1 ) . '</pre>';
}

$book = new BookProduct('Три мушкетера', 20, 1000);

// распечатаем объект
debug($book);

// попытаемся обратиться к каждому из свойств из вне класса
var_dump($book->public);
//var_dump($book->protected); // Не удается получить доступ (свойство не доступно)
//var_dump($book->private); // Неопределенное свойство (свойство не доступно)

//echo $book->getProduct();
?>

В итоге получим:
string 'PUBLIC' (length=6) - обращение внутри класса Product, где свойства объявленны
string 'PROTECTED' (length=9) - обращение внутри класса Product, где свойства объявленны
string 'PRIVATE' (length=7) - обращение внутри класса Product, где свойства объявленны
string 'PUBLIC' (length=6) - обращение к свойствам из дочернего класса BookProduct
string 'PROTECTED' (length=9) - обращение к свойствам из дочернего BookProduct

распечатываем объект (debug($book))
BookProduct Object
(
[numPages] => 1000
[name] => Три мушкетера
[price] => 20
[public] => PUBLIC
[protected:protected] => PROTECTED
[private:Product:private] => PRIVATE
)

string 'PUBLIC' (length=6) - обращение к свойствам из вне класса (index.php)





Часто в интернет-магазинах выводится старая и новая цена или цена со скидкой для товара.

Для примера создадим в классе Product свойство для скидки: public $discount = 10.

В методе getPrice()- получение цены - определим цену с учетом скидки по формуле.

И, соответственно , в информации о продукте(метод getProduct()), запишем цену со скидкой:

- Цена со скидкой: {$this->getPrice()}.


Файл Product.php


-- файл Product.php --

<?php
class Product
{
public $name;
public $price ;

// создадим свойство для скидки
public $discount = 10 ;

public function __construct($name, $price)
{
$this -> name = $name;
$this -> price = $price;
}

// метод getProduct() - будет возвращать информацию о товаре.
// информацию о цене со скидкой будем выводить не ($this->price)
// а ($this->getPrice()) - цена с учетом скидки:
public function getProduct()
{
return "<hr><b>О товаре:</b><br>
Наименование: {$this -> name}<br>
Цена со скидкой: {$this -> getPrice()}<br> ";
}

// получение цены по скидке (по формуле)
public function getPrice() {
return $this -> price - ($this -> discount/100 * $this -> price) ;
}
}
?>
Получим:
BookProduct Object
(
[numPages] => 1000
[name] => Три мушкетера
[price] => 20 // цена товара
[discount] => 10 // скидка
)
// метод getProduct() - раскомментирован
О товаре:
Наименование: Три мушкетера
Цена со скидкой: 18 // цена со скидкой
Кол-во страниц: 1000





Цену без скидки мы можем подсмотреть в коде (при модификаторе - public $price), при модификаторе видимости - private $price или protected это свойство становится недоступным и посмотреть цену можно только через getProduct().

Меняем модификатор видимости с public на protected - чтобы это свойство было доступно в классах-наследниках.

Чтобы можно было показывать не только новую цену (со скидкой), но и старую (без скидки) в классе BookProduct в методе getProduct() запишем:

- $out .= "Цена без скидки: {$this->price}<br>"


Чтобы случайно не преопределить свойство $discount (скидка), правильнее было ставить модификатор privat и приравнять скидку к нулю: private $discount = 0.



Геттеры и сеттеры




Дочерние классы получают доступ к закрытым (приватным) свойствам через метод - сеттер.

Свойство private, в отличии от protected, можно заполнить через какой-нибудь метод (сеттер).

Через геттеры и сеттеры мы получаем доступ к значениям закрытых или скрытых свойств.

Установим в классе Product геттер getDiscount() и сеттер setDiscount($discount).


Метод геттер - получает доступ к некоторому свойству, как правило к приватному или защищенному.

Метод сеттер - позволяет установить закрытое для записи свойство и записать в него некоторое значение.


Эти методы публичные и они доступны в классах-наследниках и установить скидку мы можем в каком-нибудь методе, скажем, в конструкторе (в классе BookProduct):
$this->setDiscount(5) - устанавливаем скидку в 5%.


Посмотреть скидку мы можем, вызвав ее в методе getProduct() класса BookProduct:
$out .= "Скидка: {$this->getDiscount()}%<br>".


Вне класса (файл index.php), при желании, мы можем скидку посмотреть(через геттер):
echo $book ->getDiscount().


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


В свойстве $name можно поставить модификатор private, чтобы случайно его не перезаписать.


Файл Product.php


-- файл Product.php --

<?php
class Product
{
// в свойстве $name можно поставить модификатор private,
// чтобы случайно его не перезаписать
// меняем модификатор видимости с public на private и при попытке
// вывести её вне класса произойдет ошибка - "Неопределенное свойство... "
private $name;

// $price - чтобы это свойство было доступно в классах-наследниках
// меняем private на protected
protected $price ;

// создадим свойство для скидки
// чтобы случайно не преопределить свойство $discount (скидка),
// правильнее было ставить модификатор private
// дочерние классы получают доступ к закрытым (приватным)свойствам через метод - сеттер
// свойство private, в отличии от protected, можно заполнить через какой-нибудь
// метод (сеттер)
private $discount = 0 ;

public function __construct($name, $price)
{
$this -> name = $name;
$this -> price = $price;
}

// метод getProduct() - будет возвращать информацию о товаре.
// информацию о цене со скидкой будем выводить не ($this->price)
// а ($this->getPrice()) - цена с учетом скидки:
public function getProduct() {
return "<hr><b>О товаре:</b><br>
Наименование: {$this -> name}<br>
Цена со скидкой: {$this -> getPrice()}<br> ";
}

// общие гетеры:
public function getName()
{
return $this -> name ;
}

// получение цены по скидке (по формуле)
public function getPrice() {
return $this -> price - ($this -> discount/100 * $this -> price) ;
}

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

// метод геттер - получает доступ к некоторому свойству,
// как правило к приватному или защищенному
public function getDiscount()
{
return $this -> discount ;
}
// метод сеттер - позволяет установить закрытое для записи свойство
// и записать в него некоторое значение
public function setDiscount($discount)
{
$this -> discount = $discount ;
}
}
?>




Файл BookProduct.php


-- файл BookProduct.php --

<?php
class BookProduct extends Product
{
public $numPages;

public function __construct($name, $price, $numPages)
{
parent :: __construct($name, $price);
$this -> numPages = $numPages;
$this -> setDiscount(5); // устанавливаем скидку в 5%
}

public function getProduct()
{
$out = parent :: getProduct();
$out .= "Цена без скидки: {$this -> price}<br>" ;
$out .= "Кол-во страниц:: {$this -> cpu}<br>" ;
$out .= "Скидка: {$this -> getDiscount()}%<br>" ; // дописываем скидку
return $out;
}

public function getNumPeges()
{
return $this -> numPages ;
}
}
?>





Файл index.php


-- файл index.php --

<?php
error_reporting(-1);
require_once 'classes/Product.php';
require_once 'classes/BookProduct.php';
function debug($data)
{
echo '<pre>' . print_r($data, 1 ) . '</pre>';
}

$book = new BookProduct('Три мушкетера', 20, 1000);

debug($book);

// получаем информацию о продукте с помощью метода getProduct()
echo $book -> getProduct();

// цену без скидки мы можем подсмотреть в коде при модификаторе - public $price,
// при модификаторе видимости - private $price или protected
// это свойство становится недоступным и посмотреть цену можно только через getProduct()
//echo $book->price ;

// через геттер мы можем посмотреть скидку из вне класса
echo $book -> getDiscount();
?>

Выведет:
- debug($book)-
BookProduct Object
(
[numPages] => 1000
[name:Product:private] => Три мушкетера
[price:protected] => 20
[discount:Product:private] => 5
)
- метод getProduct() -
О товаре:
Наименование: Три мушкетера
Цена со скидкой: 19
Цена без скидки: 20
Кол-во страниц: 1000
Скидка: 5%
- метод getDiscount() -
5





Рекомендуется для всех свойств изначально поставить private, а для большинста методов - public.

Постепенно, по необходимости, пожно понижать контроль доступа (для свойств).

Для свойств, которые предполагается использовать в классах-наследниках, можно поставить уже - protected. А для свойств, которые предполагается использовать из вне класса, можно поставить - public.

Для методов, которые являются служебными и пользователю не нужны для работы, можно поставить protected и реже - private.


Содержание папки 9 ("Модификаторы доступа"):


09-1






Наверх Наверх