В php не поддерживается множественное наследование при работе с классами, то есть у класса может быть только один родительский класс. И поэтому дабы избежать множественного дублирования кода были введены , так называемые трейты.
Допустим нам нужно реализовать ряд общих методов для всех классов.
Рассмотрим на примере двух классов main и child которым мы с помощью трейта functions определим общий метод profit
<?php
trait functions{ //Объявление трейта
private $percent = 7;
function profit($amount){
return $amount / 100 * $this->percent;
}
//Другие методы
}
class main{
private $amount;
use functions; //Инициализация трейта в классе
}
class child{
use functions; //Инициализация трейта в классе
}
$main = new main();
$child = new child();
echo $main->profit(1000).'<br/>';
echo $child->profit(100);
Как видите трейты чем то напоминают классы, для которых нельзя создать экземпляр объекта, но их можно включить в другие классы. Для того чтобы определить методы трейта в классе мы используем ключевое слово use и название самого трейта.
Мы также в классе может использовать несколько трейтов перечислая их через запятую, use trait1, trait2 ....;
Но даже не смотря на то что полезность трейтов не вызывает сомнений , они не позволяют изменить тип класса, в который были включены. Поэтому если трейт functions используется сразу в нескольких классах, у вас не будет общего типа, который можно было бы указать в уточнениях сигнатур методов.
К счастью трейты можно использовать вместе с интерфейсами.
interface inter{
public function profit($amount);
}
trait functions{ //Объявление трейта
private $percent = 7;
function profit($amount){
return $amount / 100 * $this->percent;
}
//Другие методы
}
class main implements inter {
private $amount;
use functions;
}
class child implements inter{
use functions;
}
$main = new main();
$child = new child();
echo $main->profit(1000).'<br/>';
echo $child->profit(100);
В этом примере мы определили метод трейта через интерфейс.
Также при использовании трейтов может возникнуть,так называемый конфликт имен.
К примеру у нас есть два трейта в которых определены методы с оодиноковыми названиями:
interface inter{
public function profit($amount);
}
trait functions{ //Объявление трейта
private $percent = 7;
function profit($amount){
return $amount / 100 * $this->percent;
}
//Другие методы
}
trait main {
function profit($amount){
return $amount / 100 * 10;
}
}
class child implements inter{
use functions,main;
}
$child = new child();
echo $child->profit(100);
Следовательно в такой ситуации у нас возникнет ошибка , так как матод profit есть в этих трейтах. Для разрешения такой проблемы используется ключевое слово insteadof
.Рассмотрим на конкретном примере:
interface inter{
public function profit($amount);
}
trait functions{ //Объявление трейта
private $percent = 7;
function profit($amount){
return $amount / 100 * $this->percent;
}
//Другие методы
}
trait main {
function profit($amount){
return $amount / 100 * 10;
}
}
class child implements inter{
use functions,main{
main::profit insteadof functions;
}
}
$child = new child();
echo $child->profit(100);
Теперь давайте рассмотрим более подробно что мы здесь понаписали такого:
Во первых как видите ошибки у нас уже нет. Благодаря использованию ключевого слова insteadof.
Во вторых у нас выполнился метод трейта profit трейта main для того чтобы выполнился метод трейта functions нам необходимо записать так:
use functions,main{
functions::profit insteadof main;
}
Как видите к объявлению наших трейтов с помощью ключевого слова use приписывается тело в котором указывается название трейта и через два двоеточия название его метода , а через ключевое слово insteadof название трейта в котором выполнение метода с таким же названием profit будет проигнорировано в пользу трейта main.
Но что если нам нужно использовать эти методы из двух трейтов с одинаковыми названиями в пределах одного класса. Для этого существуют , так называемые псевдонимы
Рассмотрим пример:
interface inter{
public function profit($amount);
}
trait functions{ //Объявление трейта
private $percent = 7;
function profit($amount){
return $amount / 100 * $this->percent;
}
//Другие методы
}
trait main {
function profit($amount){
return $amount / 100 * 10;
}
}
class child implements inter{
use functions,main{
main::profit insteadof functions;
functions::profit as functions_profit;
}
}
$child = new child();
echo $child->profit(100)."<br/>".$child->functions_profit(100);
Как видите оба метода у нас отлично отрабатывают благодаря использованию псевдонима.
Метод из profit из трейта main мы инициализируем через ключевое слово insteadof ,а метод из functions через псевдоним которому мы через ключевое слово as присвоили имя functions_profit
Ну вот в общем то и все дорогие друзья, надеюсь я смог донести до вас полезную информацию. Желаю удачи!