Π’Ρ€Π΅ΠΉΡ‚Ρ‹

Бпособ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ Π² языкС PHP ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΊΠΎΠ΄ Π²Π½Π΅Π΄Ρ€ΡΡŽΡ‚ Π² нСсвязанныС ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΠΈ классов, называСтся Ρ‚Ρ€Π΅ΠΉΡ‚Π°ΠΌΠΈ (Π°Π½Π³Π». Traits).

Π’Ρ€Π΅ΠΉΡ‚Ρ‹ β€” ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ Π² языках с ΠΎΠ΄ΠΈΠ½ΠΎΡ‡Π½Ρ‹ΠΌ наслСдованиСм Π½Π°ΠΏΠΎΠ΄ΠΎΠ±ΠΈΠ΅ PHP. Π—Π°Π΄Π°Ρ‡Π° Ρ‚Ρ€Π΅ΠΉΡ‚Π° β€” ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ΡŒ ограничСния ΠΎΠ΄ΠΈΠ½ΠΎΡ‡Π½ΠΎΠ³ΠΎ наслСдования, Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Ρ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ Π»Π΅Π³ΠΊΠΎ ΠΏΠ΅Ρ€Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π½Π°Π±ΠΎΡ€Ρ‹ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² Π² Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… нСзависимых классах, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ находятся Π² Ρ€Π°Π·Π½Ρ‹Ρ… иСрархиях наслСдования. Π‘Π΅ΠΌΠ°Π½Ρ‚ΠΈΠΊΡƒ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΠΈ Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ² ΠΈ классов ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ½ΠΈΠ·ΠΈΡ‚ΡŒ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ слоТности ΠΈ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ Ρ‚ΠΈΠΏΠΈΡ‡Π½Ρ‹Ρ… ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, свойствСнных мноТСствСнному наслСдованию ΠΈ примСсям (Π°Π½Π³Π». Mixins).

Π’Ρ€Π΅ΠΉΡ‚ ΠΏΠΎΡ…ΠΎΠΆ Π½Π° класс, Π½ΠΎ прСдназначаСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Π³Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Ρ‚ΠΎΠ½ΠΊΠΎ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΌ ΠΈ согласованным ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ. НСльзя ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ экзСмпляр Ρ‚Ρ€Π΅ΠΉΡ‚Π°. Π’Ρ€Π΅ΠΉΡ‚ дополняСт Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π½ΠΎΠ΅ наслСдованиС ΠΈ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Π²Ρ‹ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ Π³ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»ΡŒΠ½ΡƒΡŽ ΠΊΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ повСдСния; Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, Ρ‚Ρ€Π΅ΠΉΡ‚ ΠΈΠ³Ρ€Π°Π΅Ρ‚ Ρ€ΠΎΠ»ΡŒ прилоТСния ΠΊ Ρ‡Π»Π΅Π½Π°ΠΌ класса, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ наслСдования.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #1 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚Ρ€Π΅ΠΉΡ‚Π°

<?php

trait TraitA {
public function
sayHello()
{
echo
'Hello';
}
}

trait
TraitB {
public function
sayWorld()
{
echo
'World';
}
}

class
MyHelloWorld
{
use
TraitA, TraitB; // Класс Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Π²Π½Π΅Π΄Ρ€ΡΡ‚ΡŒ нСсколько Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ²

public function sayHelloWorld()
{
$this->sayHello();
echo
' ';

$this->sayWorld();
echo
"!\n";
}
}

$myHelloWorld = new MyHelloWorld();
$myHelloWorld->sayHelloWorld();

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

Hello World!

ΠŸΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚

Π§Π»Π΅Π½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ класс унаслСдовал ΠΈΠ· Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ класса, пСрСопрСдСляСтся Ρ‡Π»Π΅Π½ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ внСдрился Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠΌ. ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π° выстраиваСтся Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Ρ‚Ρ€Π΅ΠΉΡ‚Π° ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ класса, Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ класс унаслСдовал ΠΈΠ· Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ класса, ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ Ρ‚Ρ€Π΅ΠΉΡ‚Π°.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #2 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚ΠΎΠ³ΠΎ, Π² ΠΊΠ°ΠΊΠΎΠΌ порядкС выстраиваСтся ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚

ΠœΠ΅Ρ‚ΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ класс унаслСдовал ΠΈΠ· Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ класса, пСрСопрСдСляСтся ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ внСдрился Π² класс MyHelloWorld ΠΈΠ· Ρ‚Ρ€Π΅ΠΉΡ‚Π° SayWorld. ΠœΠ΅Ρ‚ΠΎΠ΄Ρ‹ Ρ‚Ρ€Π΅ΠΉΡ‚Π° Π²Π΅Π΄ΡƒΡ‚ сСбя ΠΊΠ°ΠΊ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ класса MyHelloWorld. ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π° Ρ‚Π°ΠΊΠΎΠΉ: ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ класса ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Ρ‚Ρ€Π΅ΠΉΡ‚Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ класса.

<?php

class Base
{
public function
sayHello()
{
echo
'Hello ';
}
}

trait
SayWorld
{
public function
sayHello()
{
parent::sayHello();
echo
'World!';
}
}

class
MyHelloWorld extends Base
{
use
SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

Hello World!

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #3 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ порядка ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π°

<?php

trait HelloWorld
{
public function
sayHello()
{
echo
'Hello World!';
}
}

class
TheWorldIsNotEnough
{
use
HelloWorld;

public function
sayHello()
{
echo
'Hello Universe!';
}
}

$o = new TheWorldIsNotEnough();
$o->sayHello();

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

Hello Universe!

НСсколько Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ²

Названия Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ² ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»ΡΡŽΡ‚ Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΏΡΡ‚ΡƒΡŽ Π² инструкции use, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² класс нСсколько Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ².

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #4 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ внСдрСния Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ²

<?php

trait Hello
{
public function
sayHello()
{
echo
'Hello ';
}
}

trait
World
{
public function
sayWorld()
{
echo
'World';
}
}

class
MyHelloWorld
{
use
Hello, World;

public function
sayExclamationMark()
{
echo
'!';
}
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

Hello World!

Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ²

ΠŸΡ€ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ двумя Ρ‚Ρ€Π΅ΠΉΡ‚Π°ΠΌΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° с ΠΎΠ΄Π½ΠΈΠΌ ΠΈ Ρ‚Π΅ΠΌ ΠΆΠ΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Ρ„Π°Ρ‚Π°Π»ΡŒΠ½Π°Ρ ошибка, Ссли ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ явно Π½Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΠ»ΠΈ.

ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ insteadof Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚Ρ‹ ΠΈΠΌΡ‘Π½ ΠΈ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΊΠ°ΠΊΠΎΠ³ΠΎ Ρ‚Ρ€Π΅ΠΉΡ‚Π° ΠΈΡΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠΈΠ· класса, ΠΊΠΎΠ³Π΄Π° Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚Ρ€Π΅ΠΉΡ‚Π° совпадаСт с Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ Ρ‚Ρ€Π΅ΠΉΡ‚Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΠΈ Π² этот ΠΆΠ΅ класс.

Для добавлСния псСвдонима ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ Ρ‚Ρ€Π΅ΠΉΡ‚Π° ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ as, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΡΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ as Π½Π΅ ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Ρ‹Π²Π°Π΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΈ Π½Π΅ влияСт Π½ΠΈ Π½Π° ΠΊΠ°ΠΊΠΈΠ΅ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #5 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ²

Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π² класс Talker Π²ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΠΈ Ρ‚Ρ€Π΅ΠΉΡ‚Ρ‹ A ΠΈ B. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π² Ρ‚Ρ€Π΅ΠΉΡ‚Π°Ρ… A ΠΈ B содСрТатся ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²ΡΡ‚ΡƒΠΏΠ°ΡŽΡ‚ Π² ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚, класс ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° smallTalk ΠΈΠ· Ρ‚Ρ€Π΅ΠΉΡ‚Π° B, Π° Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° bigTalk ΠΈΠ· Ρ‚Ρ€Π΅ΠΉΡ‚Π° A.

ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ as Π² классС Aliased_Talker Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ bigTalk Ρ‚Ρ€Π΅ΠΉΡ‚Π° B ΠΏΠΎ псСвдониму talk.

<?php

trait A
{
public function
smallTalk()
{
echo
'a';
}

public function
bigTalk()
{
echo
'A';
}
}

trait
B
{
public function
smallTalk()
{
echo
'b';
}

public function
bigTalk()
{
echo
'B';
}
}

class
Talker
{
use
A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}

class
Aliased_Talker
{
use
A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}

?>

ИзмСнСниС видимости ΠΌΠ΅Ρ‚ΠΎΠ΄Π°

Бинтаксис с ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ as ΡƒΠΌΠ΅Π΅Ρ‚ Ρ‚Π°ΠΊΠΆΠ΅ Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Π² классС.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #6 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ измСнСния видимости ΠΌΠ΅Ρ‚ΠΎΠ΄Π°

<?php

trait HelloWorld
{
public function
sayHello()
{
echo
'ΠŸΡ€ΠΈΠ²Π΅Ρ‚, ΠΌΠΈΡ€!';
}
}

// ИзмСним Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° sayHello
class MyClass1
{
use
HelloWorld {
sayHello as protected;
}
}

// Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ псСвдоним ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠΌ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ этого ΠΌΠ΅Ρ‚ΠΎΠ΄Π°.
// Π’ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° sayHello Π½Π΅ измСнилась
class MyClass2
{
use
HelloWorld {
sayHello as private myPrivateHello;
}
}

?>

Π˜ΠΌΠΏΠΎΡ€Ρ‚ Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ² Π² Ρ‚Ρ€Π΅ΠΉΡ‚Ρ‹

Π’Ρ€Π΅ΠΉΡ‚Ρ‹ Π²Π½Π΅Π΄Ρ€ΡΡŽΡ‚ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² классы, Π½ΠΎ ΠΈ Π² Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Ρ‚Ρ€Π΅ΠΉΡ‚Ρ‹. Π’Ρ€Π΅ΠΉΡ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΡΠΊΠΎΠΌΠΏΠΎΠ½ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ² ΠΏΡƒΡ‚Ρ‘ΠΌ ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ² Π² ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠΈ Ρ†Π΅Π»Π΅Π²ΠΎΠ³ΠΎ. Π§Π»Π΅Π½Ρ‹ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ² становятся Ρ‡Π°ΡΡ‚ΡŒΡŽ Ρ†Π΅Π»Π΅Π²ΠΎΠ³ΠΎ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #7 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ состоят ΠΈΠ· Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ²

<?php

trait Hello
{
public function
sayHello()
{
echo
'Hello ';
}
}

trait
World
{
public function
sayWorld()
{
echo
'World!';
}
}

trait
HelloWorld
{
use
Hello, World;
}

class
MyHelloWorld
{
use
HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

Hello World!

АбстрактныС Ρ‡Π»Π΅Π½Ρ‹ Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ²

Π’Ρ€Π΅ΠΉΡ‚Ρ‹ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ абстрактныС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ трСбования ΠΊ классу, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ внСдрится Ρ‚Ρ€Π΅ΠΉΡ‚. ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ общСдоступныС, Π·Π°Ρ‰ΠΈΡ‰Ρ‘Π½Π½Ρ‹Π΅ ΠΈ Π·Π°ΠΊΡ€Ρ‹Ρ‚Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹. Π”ΠΎ PHP 8.0.0 ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π»ΠΈΡΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ общСдоступныС ΠΈ Π·Π°Ρ‰ΠΈΡ‰Ρ‘Π½Π½Ρ‹Π΅ абстрактныС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹.

ΠŸΡ€Π΅Π΄ΠΎΡΡ‚Π΅Ρ€Π΅ΠΆΠ΅Π½ΠΈΠ΅

Начиная с PHP 8.0.0 выдаётся Ρ„Π°Ρ‚Π°Π»ΡŒΠ½Π°Ρ ошибка, Ссли сигнатура ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Π½Π΅ слСдуСт ΠΏΡ€Π°Π²ΠΈΠ»Π°ΠΌ совмСстимости сигнатур. РаньшС ΠΏΡ€ΠΈ нСсовпадСнии сигнатуры ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ошибка Π½Π΅ Π²Ρ‹Π΄Π°Π²Π°Π»Π°ΡΡŒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #8 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ установки Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠΉ ΠΊ классу Ρ‡Π΅Ρ€Π΅Π· абстрактный ΠΌΠ΅Ρ‚ΠΎΠ΄ Ρ‚Ρ€Π΅ΠΉΡ‚Π°

<?php

trait Hello
{
public function
sayHelloWorld()
{
echo
'Hello' . $this->getWorld();
}

abstract public function
getWorld();
}

class
MyHelloWorld
{
private
$world;

use
Hello;

public function
getWorld()
{
return
$this->world;
}

public function
setWorld($val)
{
$this->world = $val;
}
}

?>

БтатичСскиС Ρ‡Π»Π΅Π½Ρ‹ Ρ‚Ρ€Π΅ΠΉΡ‚Π°

Π’ Ρ‚Ρ€Π΅ΠΉΡ‚Π°Ρ… Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ статичСскиС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅, статичСскиС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈ статичСскиС свойства.

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅:

Начиная с PHP 8.1.0 прямой Π²Ρ‹Π·ΠΎΠ² статичСского ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΈΠ»ΠΈ прямой доступ ΠΊ статичСскому свойству Π² Ρ‚Ρ€Π΅ΠΉΡ‚Π΅ устарСли. Доступ ΠΊ статичСским ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌ ΠΈ свойствам ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽΡ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² классС, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Π½Π΅Π΄Ρ€ΠΈΠ»ΠΈ Ρ‚Ρ€Π΅ΠΉΡ‚.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #9 БтатичСскиС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅

<?php

trait Counter
{
public function
inc()
{
static
$c = 0;
$c = $c + 1;
echo
"$c\n";
}
}

class
C1
{
use
Counter;
}

class
C2
{
use
Counter;
}

$o = new C1();
$o->inc();

$p = new C2();
$p->inc();

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

1
1

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #10 БтатичСскиС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹

<?php

trait StaticExample
{
public static function
doSomething()
{
return
'Π”Π΅Π»Π°Π΅ΠΌ Ρ‡Ρ‚ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ';
}
}

class
Example
{
use
StaticExample;
}

echo
Example::doSomething();

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

Doing something

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #11 БтатичСскиС свойства

ΠŸΡ€Π΅Π΄ΠΎΡΡ‚Π΅Ρ€Π΅ΠΆΠ΅Π½ΠΈΠ΅

Π”ΠΎ PHP 8.3.0 Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠ΅ классы наслСдовали статичСскиС свойства, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ классы ΠΏΠΎΠ»ΡƒΡ‡Π°Π»ΠΈ ΠΈΠ· Ρ‚Ρ€Π΅ΠΉΡ‚Π°, Π΄Π°ΠΆΠ΅ Ссли Ρ‚Ρ€Π΅ΠΉΡ‚ явно внСдрялся Π² Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ класс. Начиная с PHP 8.3.0 статичСскоС свойство Ρ‚Ρ€Π΅ΠΉΡ‚Π° пСрСопрСдСляСт Π² Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅ΠΌ классС статичСскоС свойство, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ класс унаслСдовал ΠΈΠ· Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ.

<?php

trait T
{
public static
$counter = 1;
}

class
A
{
use
T;

public static function
incrementCounter()
{
static::
$counter++;
}
}

class
B extends A
{
use
T;
}

A::incrementCounter();

echo
A::$counter, "\n";
echo
B::$counter, "\n";

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π² PHP 8.3:

2
1

Бвойства

Π’ Ρ‚Ρ€Π΅ΠΉΡ‚Π°Ρ… доступно ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ свойств.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #12 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ опрСдСлСния свойств Π² Ρ‚Ρ€Π΅ΠΉΡ‚Π΅

<?php

trait PropertiesTrait
{
public
$x = 1;
}

class
PropertiesExample
{
use
PropertiesTrait;
}

$example = new PropertiesExample();
$example->x;

?>

Π’ классС нСльзя ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ свойство с Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΊΠ°ΠΊ Ρƒ свойства Ρ‚Ρ€Π΅ΠΉΡ‚Π°, Ссли свойство класса нСсовмСстимо со свойством Ρ‚Ρ€Π΅ΠΉΡ‚Π° ΠΏΠΎ области видимости ΠΈ Ρ‚ΠΈΠΏΡƒ, ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρƒ readonly ΠΈ Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΌΡƒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ, ΠΈΠ½Π°Ρ‡Π΅ PHP Π²Ρ‹Π΄Π°Ρ‘Ρ‚ Ρ„Π°Ρ‚Π°Π»ΡŒΠ½ΡƒΡŽ ΠΎΡˆΠΈΠ±ΠΊΡƒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #13 Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ²

<?php

trait PropertiesTrait
{
public
$same = true;
public
$different1 = false;
public
bool $different2;
public
bool $different3;
}

class
PropertiesExample
{
use
PropertiesTrait;

public
$same = true;
public
$different1 = true; // Π€Π°Ρ‚Π°Π»ΡŒΠ½Π°Ρ ошибка
public string $different2; // Π€Π°Ρ‚Π°Π»ΡŒΠ½Π°Ρ ошибка
readonly protected bool $different3; // Π€Π°Ρ‚Π°Π»ΡŒΠ½Π°Ρ ошибка
}

?>

ΠšΠΎΠ½ΡΡ‚Π°Π½Ρ‚Ρ‹

Начиная с вСрсии PHP 8.2.0 Π² Ρ‚Ρ€Π΅ΠΉΡ‚Π°Ρ… Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΠ»ΠΈ Ρ‚Π°ΠΊΠΆΠ΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ константы.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #14 ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ констант

<?php

trait ConstantsTrait
{
public const
FLAG_MUTABLE = 1;
final public const
FLAG_IMMUTABLE = 5;
}

class
ConstantsExample
{
use
ConstantsTrait;
}

$example = new ConstantsExample;
echo
$example::FLAG_MUTABLE;

?>

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

1

Π’ классС нСльзя ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ константу с Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΊΠ°ΠΊ Ρƒ константы Ρ‚Ρ€Π΅ΠΉΡ‚Π°, Ссли константа класса нСсовмСстима с константой Ρ‚Ρ€Π΅ΠΉΡ‚Π° ΠΏΠΎ области видимости, Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΌΡƒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ ΠΈ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρƒ final, ΠΈΠ½Π°Ρ‡Π΅ PHP Π²Ρ‹Π΄Π°Ρ‘Ρ‚ Ρ„Π°Ρ‚Π°Π»ΡŒΠ½ΡƒΡŽ ΠΎΡˆΠΈΠ±ΠΊΡƒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #15 Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ²

<?php

trait ConstantsTrait
{
public const
FLAG_MUTABLE = 1;
final public const
FLAG_IMMUTABLE = 5;
}

class
ConstantsExample
{
use
ConstantsTrait;

public const
FLAG_IMMUTABLE = 5; // Π€Π°Ρ‚Π°Π»ΡŒΠ½Π°Ρ ошибка
}

?>

ΠžΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹

Начиная с PHP 8.3.0 ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π»ΠΈ ΠΈΠ· Ρ‚Ρ€Π΅ΠΉΡ‚ΠΎΠ², Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΠ»ΠΈ Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ Ρ‡Π΅Ρ€Π΅Π· ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ as ΠΈ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ final. ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Ρ‚Ρ€Π΅ΠΉΡ‚Π° ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ Π·Π°ΠΏΡ€Π΅Ρ‰Π°Π΅Ρ‚ Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΌ классам ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄. Но самому классу, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π»ΠΈ Ρ‚Ρ€Π΅ΠΉΡ‚ ΠΈ Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ сдСлали ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ, ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ доступно ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #16 ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΏΡƒΡ‚Ρ‘ΠΌ добавлСния ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Π° final ΠΏΡ€ΠΈ Π²Π½Π΅Π΄Ρ€Π΅Π½ΠΈΠΈ Ρ‚Ρ€Π΅ΠΉΡ‚Π°

<?php

trait CommonTrait
{
public function
method()
{
echo
'ΠŸΡ€ΠΈΠ²Π΅Ρ‚';
}
}

class
FinalExampleA
{
use
CommonTrait {
CommonTrait::method as final; // Начиная с PHP 8.3.0 ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ final
// Π·Π°ΠΏΡ€Π΅Ρ‚ΠΈΡ‚ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π² Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… классах
}
}

class
FinalExampleB extends FinalExampleA
{
public function
method() {}
}

?>

Π’Ρ‹Π²ΠΎΠ΄ ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΡ…ΠΎΠΆ Π½Π°:

Fatal error: Cannot override final method FinalExampleA::method() in ...
οΌ‹Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ 25 notes

up
666
Safak Ozpinar / safakozpinar at gmail ΒΆ
14 years ago
Unlike inheritance; if a trait has static properties, each class using that trait has independent instances of those properties.

Example using parent class:
<?php
class TestClass {
    public static $_bar;
}
class Foo1 extends TestClass { }
class Foo2 extends TestClass { }
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: World World
?>

Example using trait:
<?php
trait TestTrait {
    public static $_bar;
}
class Foo1 {
    use TestTrait;
}
class Foo2 {
    use TestTrait;
}
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: Hello World
?>
up
462
greywire at gmail dot com ΒΆ
14 years ago
The best way to understand what traits are and how to use them is to look at them for what they essentially are:  language assisted copy and paste.

If you can copy and paste the code from one class to another (and we've all done this, even though we try not to because its code duplication) then you have a candidate for a trait.
up
256
Stefan W ΒΆ
12 years ago
Note that the "use" operator for traits (inside a class) and the "use" operator for namespaces (outside the class) resolve names differently. "use" for namespaces always sees its arguments as absolute (starting at the global namespace):

<?php
namespace Foo\Bar;
use Foo\Test;  // means \Foo\Test - the initial \ is optional
?>

On the other hand, "use" for traits respects the current namespace:

<?php
namespace Foo\Bar;
class SomeClass {
    use Foo\Test;   // means \Foo\Bar\Foo\Test
}
?>

Together with "use" for closures, there are now three different "use" operators. They all mean different things and behave differently.
up
109
t8 at AT pobox dot com ΒΆ
13 years ago
Another difference with traits vs inheritance is that methods defined in traits can access methods and properties of the class they're used in, including private ones.

For example:
<?php
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'                                                                                                                                                                                                                          

?>
up
104
chris dot rutledge at gmail dot com ΒΆ
14 years ago
It may be worth noting here that the magic constant __CLASS__ becomes even more magical - __CLASS__ will return the name of the class in which the trait is being used.

for example

<?php
trait sayWhere {
    public function whereAmI() {
        echo __CLASS__;
    }
}

class Hello {
    use sayWHere;
}

class World {
    use sayWHere;
}

$a = new Hello;
$a->whereAmI(); //Hello

$b = new World;
$b->whereAmI(); //World
?>

The magic constant __TRAIT__ will giev you the name of the trait
up
62
qeremy (!) gmail ΒΆ
11 years ago
Keep in mind; "final" keyword is useless in traits when directly using them, unlike extending classes / abstract classes.

<?php
trait Foo {
    final public function hello($s) { print "$s, hello!"; }
}
class Bar {
    use Foo;
    // Overwrite, no error
    final public function hello($s) { print "hello, $s!"; }
}

abstract class Foo {
    final public function hello($s) { print "$s, hello!"; }
}
class Bar extends Foo {
    // Fatal error: Cannot override final method Foo::hello() in ..
    final public function hello($s) { print "hello, $s!"; }
}
?>

But this way will finalize trait methods as expected;

<?php
trait FooTrait {
    final public function hello($s) { print "$s, hello!"; }
}
abstract class Foo {
    use FooTrait;
}
class Bar extends Foo {
    // Fatal error: Cannot override final method Foo::hello() in ..
    final public function hello($s) { print "hello, $s!"; }
}
?>
up
12
yeu_ym at yahoo dot com ΒΆ
7 years ago
Here is an example how to work with visiblity and conflicts.

<?php

trait A
{
    private function smallTalk()
    {
        echo 'a';
    }

    private function bigTalk()
    {
        echo 'A';
    }
}

trait B
{
    private function smallTalk()
    {
        echo 'b';
    }

    private function bigTalk()
    {
        echo 'B';
    }
}

trait C
{
    public function smallTalk()
    {
        echo 'c';
    }

    public function bigTalk()
    {
        echo 'C';
    }
}

class Talker
{
    use A, B, C {
        //visibility for methods that will be involved in conflict resolution
        B::smallTalk as public;
        A::bigTalk as public;

        //conflict resolution
        B::smallTalk insteadof A, C;
        A::bigTalk insteadof B, C;

        //aliases with visibility change
        B::bigTalk as public Btalk;
        A::smallTalk as public asmalltalk;
        
        //aliases only, methods already defined as public
        C::bigTalk as Ctalk;
        C::smallTalk as cmallstalk;
    }

}

(new Talker)->bigTalk();//A
(new Talker)->Btalk();//B
(new Talker)->Ctalk();//C

(new Talker)->asmalltalk();//a
(new Talker)->smallTalk();//b
(new Talker)->cmallstalk();//c
up
34
canufrank ΒΆ
9 years ago
A number of the notes make incorrect assertions about trait behaviour because they do not extend the class.

So, while "Unlike inheritance; if a trait has static properties, each class using that trait has independent instances of those properties.

Example using parent class:
<?php
class TestClass {
    public static $_bar;
}
class Foo1 extends TestClass { }
class Foo2 extends TestClass { }
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: World World
?>

Example using trait:
<?php
trait TestTrait {
    public static $_bar;
}
class Foo1 {
    use TestTrait;
}
class Foo2 {
    use TestTrait;
}
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: Hello World
?>"

shows a correct example, simply adding
<?php
require_once('above');
class Foo3 extends Foo2 {
}
Foo3::$_bar = 'news';
echo Foo1::$_bar . ' ' . Foo2::$_bar . ' ' . Foo3::$_bar; 

// Prints: Hello news news

I think the best conceptual model of an incorporated trait is an advanced insertion of text, or as someone put it "language assisted copy and paste." If Foo1 and Foo2 were defined with $_bar, you would not expect them to share the instance. Similarly, you would expect Foo3 to share with Foo2, and it does.

Viewing this way explains away a lot of  the 'quirks' that are observed above with final, or subsequently declared private vars,
up
9
JustAddingSomeAdditionalUseCase ΒΆ
3 years ago
I have not seen this specific use case:

"Wanting to preserve action of parent class method, the trait one calling ::parent & also the child class mehod action".

// Child class.
use SuperTrait {
  initialize as initializeOr;
}
public function initialize(array &$element) {
  ...
  $this->initializeOr($element);
}
// Trait.
public function initialize(array &$element) {
  ...
  parent::initialize($element);
}
// Parent class.
public function initialize(array &$element) {
  ...
}
up
13
qschuler at neosyne dot com ΒΆ
12 years ago
Note that you can omit a method's inclusion by excluding it from one trait in favor of the other and doing the exact same thing in the reverse way.

<?php

trait A {
    public function sayHello()
    {
        echo 'Hello from A';
    }

    public function sayWorld()
    {
        echo 'World from A';
    }
}

trait B {
    public function sayHello()
    {
        echo 'Hello from B';
    }

    public function sayWorld()
    {
        echo 'World from B';
    }
}

class Talker {
    use A, B {
        A::sayHello insteadof B;
        A::sayWorld insteadof B;
        B::sayWorld insteadof A;
    }
}

$talker = new Talker();
$talker->sayHello();
$talker->sayWorld();

?>

The method sayHello is imported, but the method sayWorld is simply excluded.
up
7
katrinaelaine6 at gmail dot com ΒΆ
8 years ago
Adding to "atorich at gmail dot com":

The behavior of the magic constant __CLASS__ when used in traits is as expected if you understand traits and late static binding (http://php.net/manual/en/language.oop5.late-static-bindings.php).

<?php

$format = 'Class: %-13s | get_class(): %-13s | get_called_class(): %-13s%s';

trait TestTrait {
    public function testMethod() {
        global $format;
        printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
    
    public static function testStatic() {
        global $format;
        printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
}

trait DuplicateTrait {
    public function duplMethod() {
        global $format;
        printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
    
    public static function duplStatic() {
        global $format;
        printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
}

abstract class AbstractClass {
    
    use DuplicateTrait;
    
    public function absMethod() {
        global $format;
        printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
    
    public static function absStatic() {
        global $format;
        printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
}

class BaseClass extends AbstractClass {
    use TestTrait;
}

class TestClass extends BaseClass { }

$t = new TestClass();

$t->testMethod();
TestClass::testStatic();

$t->absMethod();
TestClass::absStatic();

$t->duplMethod();
TestClass::duplStatic();

?>

Will output:

Class: BaseClass     | get_class(): BaseClass     | get_called_class(): TestClass    
Class: BaseClass     | get_class(): BaseClass     | get_called_class(): TestClass    
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass    
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass    
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass    
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass

Since Traits are considered literal "copying/pasting" of code, it's clear how the methods defined in DuplicateTrait give the same results as the methods defined in AbstractClass.
up
18
Edward ΒΆ
14 years ago
The difference between Traits and multiple inheritance is in the inheritance part.   A trait is not inherited from, but rather included or mixed-in, thus becoming part of "this class".   Traits also provide a more controlled means of resolving conflicts that inevitably arise when using multiple inheritance in the few languages that support them (C++).  Most modern languages are going the approach of a "traits" or "mixin" style system as opposed to multiple-inheritance, largely due to the ability to control ambiguities if a method is declared in multiple "mixed-in" classes.

Also, one can not "inherit" static member functions in multiple-inheritance.
up
13
rawsrc ΒΆ
8 years ago
About the (Safak Ozpinar / safakozpinar at gmail)'s great note, you can still have the same behavior than inheritance using trait with this approach : 
<?php

trait TestTrait {
    public static $_bar;
}

class FooBar {
    use TestTrait;
}

class Foo1 extends FooBar {

}
class Foo2 extends FooBar {

}
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: World World
up
17
marko at newvibrations dot net ΒΆ
9 years ago
As already noted, static properties and methods in trait could be accessed directly using trait. Since trait is language assisted c/p, you should be aware that static property from trait will be initialized to the value trait property had in the time of class declaration. 

Example:

<?php

trait Beer {
    protected static $type = 'Light';
    public static function printed(){
        echo static::$type.PHP_EOL;
    }
    public static function setType($type){
        static::$type = $type;
    }
}

class Ale {
    use Beer;
}

Beer::setType("Dark");

class Lager {
    use Beer;
}

Beer::setType("Amber");

header("Content-type: text/plain");

Beer::printed();  // Prints: Amber
Ale::printed();   // Prints: Light
Lager::printed(); // Prints: Dark

?>
up
9
balbuf ΒΆ
10 years ago
(It's already been said, but for the sake of searching on the word "relative"...)

The "use" keyword to import a trait into a class will resolve relative to the current namespace and therefore should include a leading slash to represent a full path, whereas "use" at the namespace level is always absolute.
up
43
ryan at derokorian dot com ΒΆ
14 years ago
Simple singleton trait.

<?php

trait singleton {    
    /**
     * private construct, generally defined by using class
     */
    //private function __construct() {}
    
    public static function getInstance() {
        static $_instance = NULL;
        $class = __CLASS__;
        return $_instance ?: $_instance = new $class;
    }
    
    public function __clone() {
        trigger_error('Cloning '.__CLASS__.' is not allowed.',E_USER_ERROR);
    }
    
    public function __wakeup() {
        trigger_error('Unserializing '.__CLASS__.' is not allowed.',E_USER_ERROR);
    }
}

/**
 * Example Usage
 */

class foo {
    use singleton;
    
    private function __construct() {
        $this->name = 'foo';
    }
}

class bar {
    use singleton;
    
    private function __construct() {
        $this->name = 'bar';
    }
}

$foo = foo::getInstance();
echo $foo->name;

$bar = bar::getInstance();
echo $bar->name;
up
5
bscheshirwork at gmail dot com ΒΆ
8 years ago
https://3v4l.org/mFuQE

1. no deprecate if same-class-named method get from trait
2. replace same-named method ba to aa in C

trait ATrait {
    public function a(){
        return 'Aa';
    }
}

trait BTrait {
    public function a(){
        return 'Ba';
    }
}

class C {
    use ATrait{
        a as aa;
    }
    use BTrait{
        a as ba;
    }
    
    public function a() {
        return static::aa() . static::ba();
    }
}

$o = new C;
echo $o->a(), "\n";

class D {
    use ATrait{
        ATrait::a as aa;
    }
    use BTrait{
        BTrait::a as ba;
    }
    
    public function a() {
        return static::aa() . static::ba();
    }
}

$o = new D;
echo $o->a(), "\n";

class E {
    use ATrait{
        ATrait::a as aa;
        ATrait::a insteadof BTrait;
    }
    use BTrait{
        BTrait::a as ba;
    }
    
    public function e() {
        return static::aa() . static::ba();
    }
}

$o = new E;
echo $o->e(), "\n";

class F {
    use ATrait{
        a as aa;
    }
    use BTrait{
        a as ba;
    }
    
    public function f() {
        return static::aa() . static::ba();
    }
}

$o = new F;
echo $o->f(), "\n";

AaAa 
AaBa 

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; E has a deprecated constructor in /in/mFuQE on line 48 
AaBa 

Fatal error: Trait method a has not been applied, because there are collisions with other trait methods on F in /in/mFuQE on line 65
up
6
Carlos Alberto Bertholdo Carucce ΒΆ
10 years ago
If you want to resolve name conflicts and also change the visibility of a trait method, you'll need to declare both in the same line:

trait testTrait{
    
    public function test(){
        echo 'trait test';
    }
    
}

class myClass{
    
    use testTrait {
        testTrait::test as private testTraitF;
    }
    
    public function test(){
        echo 'class test';
        echo '<br/>';
        $this->testTraitF();
    }
    
}

$obj = new myClass(); 
$obj->test(); //prints both 'trait test' and 'class test'
$obj->testTraitF(); //The method is not accessible (Fatal error: Call to private method myClass::testTraitF() )
up
13
D. Marti ΒΆ
13 years ago
Traits are useful for strategies, when you want the same data to be handled (filtered, sorted, etc) differently.

For example, you have a list of products that you want to filter out based on some criteria (brands, specs, whatever), or sorted by different means (price, label, whatever). You can create a sorting trait that contains different functions for different sorting types (numeric, string, date, etc). You can then use this trait not only in your product class (as given in the example), but also in other classes that need similar strategies (to apply a numeric sort to some data, etc).

<?php
trait SortStrategy {
    private $sort_field = null;
    private function string_asc($item1, $item2) {
        return strnatcmp($item1[$this->sort_field], $item2[$this->sort_field]);
    }
    private function string_desc($item1, $item2) {
        return strnatcmp($item2[$this->sort_field], $item1[$this->sort_field]);
    }
    private function num_asc($item1, $item2) {
        if ($item1[$this->sort_field] == $item2[$this->sort_field]) return 0;
        return ($item1[$this->sort_field] < $item2[$this->sort_field] ? -1 : 1 );
    }
    private function num_desc($item1, $item2) {
        if ($item1[$this->sort_field] == $item2[$this->sort_field]) return 0;
        return ($item1[$this->sort_field] > $item2[$this->sort_field] ? -1 : 1 );
    }
    private function date_asc($item1, $item2) {
        $date1 = intval(str_replace('-', '', $item1[$this->sort_field]));
        $date2 = intval(str_replace('-', '', $item2[$this->sort_field]));
        if ($date1 == $date2) return 0;
        return ($date1 < $date2 ? -1 : 1 );
    }
    private function date_desc($item1, $item2) {
        $date1 = intval(str_replace('-', '', $item1[$this->sort_field]));
        $date2 = intval(str_replace('-', '', $item2[$this->sort_field]));
        if ($date1 == $date2) return 0;
        return ($date1 > $date2 ? -1 : 1 );
    }
}

class Product {
    public $data = array();
    
    use SortStrategy;
    
    public function get() {
        // do something to get the data, for this ex. I just included an array
        $this->data = array(
            101222 => array('label' => 'Awesome product', 'price' => 10.50, 'date_added' => '2012-02-01'),
            101232 => array('label' => 'Not so awesome product', 'price' => 5.20, 'date_added' => '2012-03-20'),
            101241 => array('label' => 'Pretty neat product', 'price' => 9.65, 'date_added' => '2012-04-15'),
            101256 => array('label' => 'Freakishly cool product', 'price' => 12.55, 'date_added' => '2012-01-11'),
            101219 => array('label' => 'Meh product', 'price' => 3.69, 'date_added' => '2012-06-11'),
        );
    }
    
    public function sort_by($by = 'price', $type = 'asc') {
        if (!preg_match('/^(asc|desc)$/', $type)) $type = 'asc';
        switch ($by) {
            case 'name':
                $this->sort_field = 'label';
                uasort($this->data, array('Product', 'string_'.$type));
            break;
            case 'date':
                $this->sort_field = 'date_added';
                uasort($this->data, array('Product', 'date_'.$type));
            break;
            default:
                $this->sort_field = 'price';
                uasort($this->data, array('Product', 'num_'.$type));
        }
    }
}

$product = new Product();
$product->get();
$product->sort_by('name');
echo '<pre>'.print_r($product->data, true).'</pre>';
?>
up
12
Kristof ΒΆ
12 years ago
don't forget you can create complex (embedded) traits as well

<?php
trait Name {
  // ...
}
trait Address {
  // ...
}
trait Telephone {
  // ...
}
trait Contact {
  use Name, Address, Telephone;
}
class Customer {
  use Contact;
}
class Invoce {
  use Contact;
}
?>
up
4
Oddant ΒΆ
13 years ago
I think it's obvious to notice that using 'use' followed by the traits name must be seen as just copying/pasting lines of code into the place where they are used.
up
5
artur at webprojektant dot pl ΒΆ
13 years ago
Trait can not have the same name as class because it will  show: Fatal error: Cannot redeclare class
up
1
guidobelluomo at gmail dot com ΒΆ
5 years ago
If you override a method which was defined by a trait, calling the parent method will also call the trait's override. Therefore if you need to derive from a class which has a trait, you can extend the class without losing the trait's functionality:

<?php

trait ExampleTrait
{
    public function output()
    {
        parent::output();
        echo "bar<br>";
    }
}

class Foo
{
    public function output()
    {
        echo "foo<br>";
    }
}

class FooBar extends Foo
{
    use ExampleTrait;
}

class FooBarBaz extends FooBar
{
    use ExampleTrait;
    public function output()
    {
        parent::output();
        echo "baz";
    }
}

(new FooBarBaz())->output();
?>

Output:
foo
bar
baz
up
2
cody at codysnider dot com ΒΆ
9 years ago
/*
DocBlocks pertaining to the class or trait will NOT be carried over when applying the trait.

Results trying a couple variations on classes with and without DocBlocks that use a trait with a DocBlock
*/

<?php

/**
 * @Entity
 */
trait Foo
{
    protected $foo;
}

/**
 * @HasLifecycleCallbacks
 */
class Bar
{
    use \Foo;
    
    protected $bar;
}

class MoreBar
{
    use \Foo;
    
    protected $moreBar;
}

$w = new \ReflectionClass('\Bar');
echo $w->getName() . ":\r\n";
echo $w->getDocComment() . "\r\n\r\n";

$x = new \ReflectionClass('\MoreBar');
echo $x->getName() . ":\r\n";
echo $x->getDocComment() . "\r\n\r\n";

$barObj = new \Bar();
$y = new \ReflectionClass($barObj);
echo $y->getName() . ":\r\n";
echo $y->getDocComment() . "\r\n\r\n";

foreach($y->getTraits() as $traitObj) {
    echo $y->getName() . " ";
    echo $traitObj->getName() . ":\r\n";
    echo $traitObj->getDocComment() . "\r\n";
}

$moreBarObj = new \MoreBar();
$z = new \ReflectionClass($moreBarObj);
echo $z->getName() . " ";
echo $z->getDocComment() . "\r\n\r\n";

foreach($z->getTraits() as $traitObj) {
    echo $z->getName() . " ";
    echo $traitObj->getName() . ":\r\n";
    echo $traitObj->getDocComment() . "\r\n";
}
up
0
84td84 at gmail dot com ΒΆ
11 years ago
A note to 'Beispiel #9 Statische Variablen'. A trait can also have a static property:

trait Counter {
    static $trvar=1;

    public static function stfunc() {
        echo "Hello world!"
    }
}

class C1 {
    use Counter;
}

print "\nTRVAR: " . C1::$trvar . "\n";   //prints 1

$obj = new C1();
C1::stfunc();   //prints  Hello world!
$obj->stfunc();   //prints Hello world!

A static property (trvar) can only be accessed using the classname (C1).
But a static function (stfunc) can be accessed using the classname or the instance ($obj).