Трейты
28 февраля 2016
Трейты — это конструкция, похожая на класс (содержит методы и свойства, области доступа, может иметь абстрактные методы).
Особенности трейтов:
Пример двух трейтов, используемых в одном классе:
Особенности трейтов:
- Не могут вызываться напрямую, но могут множественно наследоваться классами и другими трейтами;
- Объявляется с помощью ключевого слова trair;
- Подключаются к классу при помощи оператора use;
- Методы трейта переопределяют методы родительских классов.
Пример двух трейтов, используемых в одном классе:
//Трейт Лицо
trait sp_person
{
public $name = '';
public $surname = '';
//Возврашает заголовок лица (абстрактная функция)
abstract public function get_person_caption();
}
//Трейт Контакты
trait sp_contacts
{
private $contacts = array();
// Устанавливает значение контакта
// @param string $code - код контакта
// @param string $value - значение контакта
// @return bool
public function set_contact($code, $value)
{
$code = trim($code);
if($code=='')
{
return false;
}
else
{
$this->contacts[$code] = $value;
return true;
}
}
// Возвращает значение контакта
// @param string $code - код контакта
// @return string
public function get_contact($code)
{
$code = trim($code);
if($code!='' && isset($this->contacts[$code])) return $this->contacts[$code];
else return NULL;
}
// Возвращает массив с контактными данными
// @return array
public function get_contacts()
{
return $this->contacts;
}
}
//Работник
class worker
{
use sp_person, sp_contacts;
// Возврашает заголовок лица
// @return string
public function get_person_caption()
{
$caption = array();
if($this->name!='') $caption[] = $this->name;
if($this->surname!='') $caption[] = $this->surname;
if(count($caption)==0) $caption[] = 'Аноним';
return implode(' ', $caption);
}
}
$w = new worker();
$w->name = 'Иван';
$w->surname = 'Иванов';
echo $w->get_person_caption(); //Выведет 'Иван Иванов'
$w->set_contact('telephone', '+77777777777');
$w->set_contact('email', 'test@test.ru');
$w->set_contact('country', 'Россия');
/*
Будет выведен массив:
Array
(
[telephone] => +77777777777
[email] => test@test.ru
[country] => Россия
)
*/
echo '<pre>'.print_r($w->get_contacts(), true).'</pre>';
Совпадение свойств
При подключении к классу трейтов, у которых есть свойства с одинаковым именем, возникнет ошибка ТРЕЙТ_1 and ТРЕЙТ_2 define the same property ($ИМЯ_СВОЙСТВА) in the composition of words. However, the definition differs and is considered incompatible. Но ошибка не возникнет, если совпадающие свойства имеют одинаковое начальное значение и область видимости.Совпадение методов
Если в трейтах совпадают имена методов, то при подключении этих трейтов к классу возникнет фатальная ошибка Trait method ИМЯ_МЕТОДА_ТРЕЙТА has not been applied, because there are collisions with other trait methods on ИМЯ_КЛАССА. Для обхода такой ситуации в конструкции use с помощью оператора insteadof указывают какой метод из трейта должен использоваться вместо дублирующего метода.trait word_ru
{
public static function hello()
{
return 'Привет';
}
}
trait word_en
{
public static function hello()
{
return 'Hello';
}
}
class words
{
use word_ru, word_en
{
word_ru::hello insteadof word_en; //Использовать word_ru::hello вместо такого же метода в word_en
}
}
echo words::hello(); //Выведет 'Привет'
Изменение области видимости метода и создание синонима
Для изменения области видимости метода, а так же для создания синонима (псевдонима) метода используется оператор as, который указывается в теле use при подключении трейтов. Пример кода:trait lang_ru
{
private static function get_hello()
{
return 'Привет';
}
}
class words
{
use lang_ru
{
get_hello as protected; //Делаем метод защищённым
get_hello as public hello; //Создаём открытый синоним функции
}
}
echo words::hello(); //Выведет 'Привет'
echo words::get_hello(); //Выведет ошибку 'Fatal error: Uncaught Error: Call to protected method words::get_hello() from context