ООП PHP
Трейты
Трейты: php.net
PHP не поддерживает множественное наследование. Частично эту проблему можно решить либо с помощью интерфейсов (можно реализовать несколько интерфейсов), либо цепочки классов (создав один класс, который будет наследовать другой класс, в свою очередь, второй класс будет наследовать третий и т. д.). Однако, данный момент, тоже имеет свои неудобства, свои ограничения.
Представим, что у нас появилось такое свойство (для гаджета), как $color. Если поместить его в свойста общего класса Product, то у нас получится: и в книге, и в ноутбуке есть характеристика - цвет.
Файл Product.php
-- файл Product.php --
<?php
namespace ;
abstract class
{
private $name;
protected $price;
private $discount = 0;
// Представим, что у нас появилось такое свойство (для гаджета), как color
private $color;
public function ($name, $price)
{
$this -> name = $name;
$this -> price = $price;
}
public function ()
{
return "<hr><b>О товаре:</b><br>
Наименование: {$this -> name}<br>
Цена со скидкой: {$this -> ()}<br>";
}
public function ()
{
return $this -> name;
}
public function ()
{
return $this -> price - ($this -> discount/100 * $this -> price);
}
public function ()
{
return $this -> discount;
}
public function ($discount)
{
$this -> discount = $discount;
}
abstract protected function ($name, $price);
}
?>
Файл index.php:
-- файл index.php --
<?php
use \{ , };
use \ \{ , };
(-1);
function ($data)
{
echo '<pre>' . ($data, 1 ) . '</pre>';
}
function ($product)
{
echo "<p>Предлагаем чехол для гаджета {$product -> ()} </p>";
}
$book = new ('Три мушкетера', 20, 1000);
$notebook = new ('Dell', 1000, 'Intel');
($notebook);
($book);
($notebook);
?>
Получим:
Предлагаем чехол для гаджета Dell
app\BookProduct Object
(
[numPages] => 1000
[name:core\Product:private] => Три мушкетера
[price:protected] => 20
[discount:core\Product:private] => 5
[color:core\Product:private] => - и в книге, и в ноутбуке есть цвет
)
app\NotebookProduct Object
(
[cpu] => Intel
[name:core\Product:private] => Dell
[price:protected] => 1000
[discount:core\Product:private] => 0
[color:core\Product:private] => - и в книге, и в ноутбуке есть цвет
)
- для книги такая характеристика, как цвет - не нужна. Выносить такое свойство ($color) в общий класс нецелесообразно.
Вынесем это свойство в частный класс (NotebookProduct), там где оно может непосредственно использоватся. Получим, что в книгах свойства цвет - нет, а в ноутбуках это свойство есть.
Получим:
Предлагаем чехол для гаджета Dell
app\BookProduct Object
(
[numPages] => 1000
[name:core\Product:private] => Три мушкетера
[price:protected] => 20
[discount:core\Product:private] => 5
)
app\NotebookProduct Object
(
[cpu] => Intel
[color:app\NotebookProduct:private] =>
- свойство цвет есть только для ноутбука
[name:core\Product:private] => Dell
[price:protected] => 1000
[discount:core\Product:private] => 0
)
Однако, у нас могут появиться какие-то гаджеты, которые не имеют свойства "цвет". Например, планшет - не имеет такую характеристику, как цвет.
И встают проблема: либо мы опять дублируем код, создавая свойство "цвет" для любых продуктов типа "гаджет" (ноутбук, телефон, планшет и т. д.), либо же создать два промежуточных класса. Один класс будет наследовать например, ноутбук и телефон (в которых есть сойство "цвет"), второй - планшет (который не имеет свойства "цвет").
Чтобы решить эту проблему используются трейты
Трейты
Трейт - это метод для повторного использования кода.
Трейт - по сути дела, тот же самый класс, но только класс, от которого нельзя создать объект.
В отличии от интерфейсов трейты могут иметь реализацию. Трейт можно включить в любой класс, от которого можно создать объект.
Трейт, в отличии от йнтерфейса, не меняет тип объекта, но меняет структуру класса.
Создадим отдельную папку trait в папке core, и в ней создадим трейт, который будет работать с цветом и назовем его - TColor.php. Из файла NotebookProduct.php убираем свойство $color и вместо него мы будем подключать трейт.
Файл TColor.php
-- файл TColor.php --
<?php
// добавляем пространство имен
namespace \ ;
// трейт объявляется с помощью ключевого слова trait; и назовем его по имени файла TColor
trait
{
// внутри идет реализация:
// нам необходимо наше свойство $color и нам понадобятся два метода: гетер и сетер
private $color;
// гетер
public function ()
{
return $this -> color;
}
// сетер
public function ($color)
{
$this -> color = $color;
return $this;
}
}
?>
В файле NotebookProduct.php подключаем с помощью ключевого слова use и имени трейта наш трейт - TColor, а также импортируем пространство имен: use core\traits\TColor;
Теперь, при распечатки объекта (debug($notebook)), видим, что у объекта $notebook появилось новое свойство - $color, а у объекта $book - ничего не изменилось
Файл NotebookProduct.php:
-- файл NotebookProduct.php --
<?php
namespace ;
use \ \ ;
use \ ;
use \ \ ; // импортируем постранство имен
// NotebookProduct, Product, IGadget ---- тип объекта
class extends implements
{
// подключаем трейт с помощью ключевого слова use (имя трейта) -
// - фактически, мы сделали инклюд логики файла TColor.php:
use ;
public $cpu;
public function ($name, $price, $cpu)
{
parent :: ($name, $price);
$this -> cpu = $cpu;
}
public function ()
{
}
public function ()
{
$out = parent :: ();
$out .= "Процессор: {$this -> cpu}<br>";
return $out;
}
public function ()
{
return $this -> cpu;
}
public function ($name, $price, $cpu = '')
{
// --------------------------
($name);
($price);
($cpu);
}
}
?>
После обновления страницы получим:
Предлагаем чехол для гаджета Dell
app\BookProduct Object
(
[numPages] => 1000
[name:core\Product:private] => Три мушкетера
[price:protected] => 20
[discount:core\Product:private] => 5
)
app\NotebookProduct Object
(
[cpu] => Intel
[name:core\Product:private] => Dell
[price:protected] => 1000
[discount:core\Product:private] => 0
[color:app\NotebookProduct:private] =>
- свойство цвет есть только для ноутбука
)
Тип нашего объекта по прежнему будет -> NotebookProduct, Product, IGadget; но изменилась структура класса - используя use TColor мы фактически сделали инклюд, то есть фактически, мы взяли все содержимое кода трейта и вставили в класс NotebookProduct.
То есть, если у нас есть участок кода, который можно использовать в каких-то некоторых классах, то можно создать трейт и импортировать его в нужные классы и нужная логика из этого трейта будет подключаться в тот класс, куда мы его импортируем.
Содержание папки 14 ("Трейты"):
Наверх Наверх