Новая фича, которая появилась с бетой PHP 5.4, называется Трейт (Типаж).
Трейт - единица повторного использования кода.
Используется для реализации множественного наследования, так то можно и с помощью повторного кода это сделать, но это неправильно, так как идет усложнение кода, а здесь просто все делается в одну строчку.
Так то можно и с помощью интерфейсов реализовать множественное наследование, но трейты намного удобнее (лично для меня).
Совет для лучшего понимания и осмысления трейтов:
Это просто копипаст, то есть как будто в классе взяли и сделал include 'some.php' с каким то методом.
Еще информацию можно найти здесь:
http://habrahabr.ru/post/130000/
http://www.php.net/manual/ru/language.oop5.traits.php
Правила:
- Трейт нельзя инстанцировать в какой-то объект (сначала надо добавить его в класс).
- В трейт можно добавлять и методы и переменные.
- Классы могут сколько угодно содержать трейтов.
- Трейт может содержать другие трейты
- Если разные классы будут использоват трейт со статическим свойством, то значение этого свойства будет разное.
- В отличие от обычного наследования.
- В типаже можно объявлять статические методы, но нельзя объявлять статические свойства. Но это можно обойти.
1. Синтаксис
Трейт похож на класс, его объявление начинается со слова trait:
trait TSingleton {
private static $_instance = null;
public static function getInstance() {
if (null === self::$_instance)
{
self::$_instance = new self();
}
return self::$_instance;
}
}
class FrontController {
use TSingleton;
}
// Также может быть использован в уже унаследованном классе
class WebSite extends SomeClass {
use TSingleton;
}
2. Класс может также содержать неограниченное количество трейтов
(пример взят с википедии), трейты указываются через запятую:
// Шаблон
trait TBounding {
public $x, $y, $width, $height;
}
trait TMoveable {
public function moveTo($x, $y) {
// ...
}
}
trait TResizeable {
public function resize($newWidth, $newHeight) {
// ...
}
}
// Несколько трейтов
class Rectangle {
use TBounding, TMoveable, TResizeable;
function fillColor($color) {
// ...
}
}
3. Трейт может содержать другие трейты:
trait HelloWorld
{
use Hello, World;
}
class MyWorld
{
use HelloWorld;
}
4. Трейты и порядок выполнения.
Не стоит забывать, что:1)Сначала:
Методы трейта переписывают унаследованные методы родительского класса
2)Потом уже:
Методы определенные в текущем классе переписывают методы из трейта
trait Hello
{
function sayHello() {
return "Hello";
}
function sayWorld() {
return "Trait World";
}
function sayHelloWorld() {
echo $this->sayHello() . " " . $this->sayWorld();
}
function sayBaseWorld() {
echo $this->sayHello() . " " . parent::sayWorld();
}
}
class Base
{
function sayWorld(){
return "Base World";
}
}
class HelloWorld extends Base
{
use Hello;
function sayWorld() {
return "World";
}
}
$h = new HelloWorld();
$h->sayHelloWorld(); // Hello World
$h->sayBaseWorld(); // Hello Base World
Объяснение:
Мы имеем результат Hello World, так как у нас в текущем классе (производном) определен метод, который ПЕРЕКРЫВАЕТ метод из трейта.
Поэтому,если мы хотим, чтобы HelloWorld объект выводил также Base World, нам необходимо использовать ключевое слово ::parent.
5. Конфликт имен
Может возникнуть ситуация, что два трейта содержат функцию с одинаковым именем, тогда PHP выкинет fatal error ошибку
trait Game
{
function play() {
echo "Playing a game";
}
}
trait Music
{
function play() {
echo "Playing music";
}
}
class Player
{
use Game, Music;
}
$player = new Player();
$player->play();
Решение:
Нужно использовать ключевое слово instead:
class Player
{
use Game, Music {
Music::play insteadof Game;
}
}
$player = new Player();
$player->play(); //Выведет: Playing music
Категория отличие от обычного наследования:
6. Статические свойства в трейтах
Как мы помним, в наследовании, если наследуется класс со статическим свойством, то это статическое поле содержит одно и то же значение, в трейтах не так, класс в трейтах использует разные объекты;Пример на родительских классах:
class TestClass {
public static $_bar;
}
class Foo1 extends TestClass { }
class Foo2 extends TestClass { }
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Выведет: World World
Пример с использованием трейта:
trait TestTrait {
public static $_bar;
}
class Foo1 {
use TestTrait;
}
class Foo2 {
use TestTrait;
}
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Выведете: Hello World
7. Доступ из трейта к свойствам наследуемого класса:
Трейт иммет доступ к свойствам класса, который унаследовал трейт, в отличие от обычного наследования:
trait MyTrait{
protected function accessVar() {
return $this->var;
}
}
class TraitUser{
use MyTrait;
private $var = 'var';
public function getVar() {
return $this->accessVar();
}
}
$t = new TraitUser();
echo $t->getVar(); // -> 'var'
0 коммент.:
Отправить комментарий