欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

php Trait

shiping1 的头像
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。

Example #1 Trait 示例

<?php
trait ezcReflectionReturnInfo {
    function 
getReturnType() { /*1*/ }
    function 
getReturnDescription() { /*2*/ }
}

class 
ezcReflectionMethod extends ReflectionMethod {
    use 
ezcReflectionReturnInfo;
    
/* ... */
}

class 
ezcReflectionFunction extends ReflectionFunction {
    use 
ezcReflectionReturnInfo;
    
/* ... */
}
?>

优先级 ¶

从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。

Example #2 优先顺序示例

从基类继承的成员被插入的 SayWorld Trait 中的 MyHelloWorld 方法所覆盖。其行为 MyHelloWorld 类中定义的方法一致。优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。

<?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!

Example #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!

多个 trait ¶

通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。

Example #4 多个 trait 的用法

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

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

class 
MyHelloWorld {
    use 
HelloWorld;
    public function 
sayExclamationMark() {
        echo 
'!';
    }
}


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

以上例程会输出:

Hello World!

冲突的解决 ¶

如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。

为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。

以上方式仅允许排除掉其它方法,as 操作符可以将其中一个冲突的方法以另一个名称来引入。

Example #5 冲突的解决

在本例中 Talker 使用了 trait A 和 B。由于 A 和 B 有冲突的方法,其定义了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk。

Aliased_Talker 使用了 as 操作符来定义了 talk 来作为 B 的 bigTalk 的别名。

<?php
trait {
    public function 
smallTalk() {
        echo 
'a';
    }
    public function 
bigTalk() {
        echo 
'A';
    }
}

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

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

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

?>

修改方法的访问控制 ¶

使用 as 语法还可以用来调整方法的访问控制。

Example #6 修改方法的访问控制

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


// 修改 sayHello 的访问控制
class MyClass1 {
    use 
HelloWorld sayHello as protected; }
}


// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化

class MyClass2 {
    use 
HelloWorld sayHello as private myPrivateHello; }
}

?>

从 trait 来组成 trait ¶

正如 class 能够使用 trait 一样,其它 trait 也能够使用 trait。在 trait 定义时通过使用一个或多个 trait,能够组合其它 trait 中的部分或全部成员。

Example #7 从 trait 来组成 trait

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

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

trait 
HelloWorld {
    use 
HelloWorld;
}

class 
MyHelloWorld {
    use 
HelloWorld;
}


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

以上例程会输出:

Hello World!

Trait 的抽象成员 ¶

为了对使用的类施加强制要求,trait 支持抽象方法的使用。

Example #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;
    }
}

?>

Trait 的静态成员 ¶

Traits 可以被静态成员静态方法定义。

Example #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(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>

Example #10 静态方法

<?php
trait StaticExample {
    public static function 
doSomething() {
        return 
'Doing something';
    }
}

class 
Example {
    use 
StaticExample;
}


Example::doSomething();
?>

属性 ¶

Trait 同样可以定义属性。

Example #11 定义属性

<?php
trait PropertiesTrait {
    public 
$x 1;
}

class 
PropertiesExample {
    use 
PropertiesTrait;
}


$example = new PropertiesExample;
$example->x;
?>

如果 trait 定义了一个属性,那类将不能定义同样名称的属性,否则会产生一个错误。如果该属性在类中的定义与在 trait 中的定义兼容(同样的可见性和初始值)则错误的级别是 E_STRICT,否则是一个致命错误。

Example #12 解决冲突

<?php
trait PropertiesTrait {
    public 
$same true;
    public 
$different false;
}

class 
PropertiesExample {
    use 
PropertiesTrait;
    public 
$same true// Strict Standards
    
public $different true// 致命错误
}
?>
add a note add a note

User Contributed Notes 32 notes

Safak Ozpinar / safakozpinar at gmail ¶
4 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
?>
greywire at gmail dot com ¶
4 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.
Stefan W ¶
2 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.
atorich at gmail dot com ¶
2 years ago
add to "chris dot rutledge at gmail dot com":
__CLASS__ will return the name of the class in which the trait is being used (!) not the class in which trait method is being called:

<?php
trait TestTrait {
    public function 
testMethod() {
        echo 
"Class: " __CLASS__ PHP_EOL;
        echo 
"Trait: " __TRAIT__ PHP_EOL;
    }
}

class 
BaseClass {
    use 
TestTrait;
}

class 
TestClass extends BaseClass {

}


$t = new TestClass();
$t->testMethod();

//Class: BaseClass
//Trait: TestTrait
qeremy (!) gmail ¶
1 year 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!"; }
}

?>
chris dot rutledge at gmail dot com ¶
4 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
t8 at AT pobox dot com ¶
3 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'                                                                                                                                                                                                                          

?>
ryan at derokorian dot com ¶
4 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;
karolis at iwsolutions dot ie ¶
3 years ago
Not very obvious but trait methods can be called as if they were defined as static methods in a regular class 

<?php 
trait Foo 
    function 
bar() { 
        return 
'baz'
    } 


echo 
Foo::bar(),"\\n"
?>
Edward ¶
4 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.
qschuler at neosyne dot com ¶
2 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 {
    public function 
sayHello()
    {
        echo 
'Hello from A';
    }

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

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

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

class 
Talker {
    use 
A{
        
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.
Anonymous ¶
4 years ago
Traits can not implement interfaces.
(should be obvious, but tested is tested)
anthony bishopric ¶
4 years ago
The magic method __call works as expected using traits.

<?php 
trait Call_Helper{
    
    public function 
__call($name$args){
        return 
count($args);
    }
}

class 
Foo{
    use 
Call_Helper;
}


$foo = new Foo();
echo 
$foo->go(1,2,3,4); // echoes 4
Vasyl Sovyak ¶
4 months ago
<?php
trait A
{
    public function 
bar()
    {
        echo 
'A::bar';
    }
}

trait 
B
{
    public function 
bar()
    {
        echo 
'B::bar';
    }
}

trait 
C
{
    public function 
bar()
    {
        echo 
'C::bar';
    }
}

class 
Foo
{
    use 
AB{
        
C::bar insteadof AB;
    }
}


$foo = new Foo();
$foo->bar(); //C::bar
D. Marti ¶
3 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] ? -);
    }
    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] ? -);
    }
    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 ? -);
    }
    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 ? -);
    }
}

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->datatrue).'</pre>';
?>
Jason dot Hofer dot deletify dot this dot part at gmail dot com ¶
4 years ago
A (somewhat) practical example of trait usage.

Without traits:

<?php

class Controller {
  
/* Controller-specific methods defined here. */
}

class 
AdminController extends Controller {
  
/* Controller-specific methods inherited from Controller. */
  /* Admin-specific methods defined here. */

}

class 
CrudController extends Controller {
  
/* Controller-specific methods inherited from Controller. */
  /* CRUD-specific methods defined here. */

}

class 
AdminCrudController extends CrudController {
  
/* Controller-specific methods inherited from Controller. */
  /* CRUD-specific methods inherited from CrudController. */
  /* (!!!) Admin-specific methods copied and pasted from AdminController. */

}

?>

With traits:

<?php

class Controller {
  
/* Controller-specific methods defined here. */
}

class 
AdminController extends Controller {
  
/* Controller-specific methods inherited from Controller. */
  /* Admin-specific methods defined here. */

}

trait 
CrudControllerTrait {
  
/* CRUD-specific methods defined here. */
}

class 
AdminCrudController extends AdminController {
  use 
CrudControllerTrait;
  
/* Controller-specific methods inherited from Controller. */
  /* Admin-specific methods inherited from AdminController. */
  /* CRUD-specific methods defined by CrudControllerTrait. */

}

?>
ryanhanekamp at yahoo dot com ¶
3 years ago
Using AS on a __construct method (and maybe other magic methods) is really, really bad. The problem is that is doesn't throw any errors, at least in 5.4.0. It just sporadically resets the connection. And when I say "sporadically," I mean that arbitrary changes in the preceding code can cause the browser connection to reset or not reset *consistently*, so that subsequent page refreshes will continue to hang, crash, or display perfectly in the same fashion as the first load of the page after a change in the preceding code, but the slightest change in the code can change this state. (I believe it is related to precise memory usage.)

I've spent a good part of the day chasing down this one, and weeping every time commenting or even moving a completely arbitrary section of code would cause the connection to reset. It was just by luck that I decided to comment the

"__construct as primitiveObjectConstruct"

line and then the crashes went away entirely.

My parent trait constructor was very simple, so my fix this time was to copy the functionality into the child __construct. I'm not sure how I'll approach a more complicated parent trait constructor.
Kristof ¶
1 year ago
don't forget you can create complex (embedded) traits as well

<?php
trait Name {
  
// ...
}
trait 
Address {
  
// ...
}
trait 
Telephone {
  
// ...
}
trait 
Contact {
  use 
NameAddressTelephone;
}
class 
Customer {
  use 
Contact;
}
class 
Invoce {
  use 
Contact;
}

?>
ryan dot yoosefi at gmail dot com ¶
1 year ago
Visibility in traits is not shared between trait users.

<?php

trait {
    protected 
$secret 1;
}

class 
{
    use 
T;
    public function 
peek Y $y ) {
        echo 
$y->secret;
    }
}

class 
{
    use 
T;
}

(new 
X)->peek(new Y); // Fatal:  Cannot access protected property Y::$secret
?>

This is as expected when thinking of traits as language assisted copy-paste.
Carlos Alberto Bertholdo Carucce ¶
17 days 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() )
artur at webprojektant dot pl ¶
3 years ago
Trait can not have the same name as class because it will  show: Fatal error: Cannot redeclare class
balbuf ¶
2 months 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.
84td84 at gmail dot com ¶
1 year 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).
aram dot petrosyan dot 88 at gmail dot com ¶
1 year ago
It's possible to define abstract function in a trait as static and implement non-static version of the function , and it will works. Like this

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

class traitTest
{
    use B;

    public static function talk()
    {
        echo 111;
    }
}

Also, it's possible to define abstract non static , and implement static version. 

Can't understand , is this a bug or it's a feature :)
Oddant ¶
2 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.
angel dot ayora at gmail dot com ¶
1 year ago
The traits can be used if are inherited from a parent class, but the trait still belong to parent class:

<?php

trait Singleton
{
    private static 
$instance null;

    public static function 
singleton()
    {
        if( 
self::$instance == null )
        {
            
self::$instance = new self();
        }
        return 
self::$instance;
    }
}

class 
A
{
    use 
Singleton;
    private function 
__construct(){}
}

class 
extends A
{
    private function 
__construct(){}
}


$b B::singleton();
echo 
get_class($b); //Output: A

?>
Serafim ¶
3 years ago
Another useful property of traits:
<?php
namespace Traits;
trait 
Properties{
    public function 
__get($var){
        
$var '_' $var;
        
$getter '_get' $var;
        
        if(
method_exists($this$getter)){
            try{
                
$val $this->$getter();
            }catch(\
Exception $e){
                throw new \
Exception($e);
            }
            return 
$val;
        }
        throw new \
Exception('Can not get property: ' $var ', method ' $getter ' not exists');
    }
    
    public function 
__set($var$val){
        
$var '_' $var;
        
$setter '_set' $var;
        
        if(
method_exists($this->$setter) && isset($this->$var)){
            try{
                
$setval $this->$setter($val);
            }catch(\
Exception $e){
                throw new \
Exception($e);
            }
            
$this->$var = ($setval === NULL) ? $this->$var $setval;
        }else{
            throw new \
Exception('Can not set property: ' $var ', method ' $setter ' not exists');
        }
    }
}

class 
Some{
  use \
Chidori\Traits\Properties;
  
  
// Magic begin
  
protected $_var 42;
  protected function 
_get_var(){ return $this->_var; }
  protected function 
_set_var($val){ return NULL; }
}


$s = new Some();
$s->var 23; \\ set value
echo $s->var; \\ return 42where is my 23? =)
?>
vijit at mail dot ru ¶
7 months ago
Example #9 "Static Variables" is useless. Variable $c in function will be static anyway, this is provided by scope of function. And the result will be the same without directive "static".
Nanhe Kumar ¶
1 year ago
<?php

//Precedence Order Example with base class
trait {

    public function 
foo() {
        echo 
"T";
    }

}

class 
{

    public function 
foo() {
        echo 
"A";
    }

}

class 
extends {

    use 
T;
}


$o = new B();
$o->foo(); //Prints : T
?>
contato at williamsantana dot com dot br ¶
2 years ago
Please note that a trait cannot extend a class. Traits can only contain another traits by using 'use' keyword. Things like 

<?php
    
trait DetailedException extends Exception {}
?>

will not work. Be careful.

Cheers.
tomasz at marcinkowski dot pl ¶
2 years ago
Unlike the __CLASS__ constant, which returns name of a class implementing a trait, the __METHOD__ constant returns the trait method name. You might find it useful.

Example:

<?php

namespace XXX;

trait 
Ta {
  public function 
test1() {
    return 
sprintf('class: %s, method: %s, trait: %s'__CLASS____METHOD____TRAIT__);
  }
}

class 
{
  use 
Ta;
}


$a = new A();
var_dump($a->test1()); // class: XXX\A, method: XXX\Ta::test1, trait: XXX\Ta

?>
heli ¶
4 months ago
class first_class
   {
     // Using the Trait Here
     use first_trait;
   }

   $obj = new first_class();

   // Executing the method from trait
   $obj->first_method(); // valid
   $obj->second_method(); // valid
来自 http://www.php.net/manual/zh/language.oop5.traits.php
普通分类: