据说,为了弥补php单继承的不足,从PHP5.4起,引入了traits特性。使得php可以通过trait实现多重继承。

举例:

<?php
trait Foo {

    public function test(){
        echo "Testing";
    }
}

class Person {

    //在类中使用traits
    use Foo;

    public function newTest(){
        echo "New testing";
    }
}

//实例化对象
$person = new Person();
$person->newTest(); // New testing
$person->test();  // Testing

还可以像这样,同时引入多个Traits

<?php
trait includeTrait {
    public function includeMethod(){
        echo "这个trait将被别的trait包含";
    }
}

trait firstTrait {

    //trait中也可以包含trait
    use includeTrait;

    public function firstMethod(){
        echo "method1";
    }
}

trait secondTrait {

    //trait中也可以使用抽象方法
    abstract function secondMethod();
}

class Foo {

    //同时使用多个trait
    use firstTrait, secondTrait;

    //重写抽象方法
    public function secondMethod(){
        echo "method2";
    }
}

$foo = new Foo();

$foo->includeMethod();  //"这个trait将被别的trait包含"
$foo->firstMethod();    //"method1"
$foo->secondMethod();   //"method2"

如果命名冲突了呢?

<?php

    trait T1 {

        public function sameMethodName(){
            echo "T1.";
        }
    }

    trait T2 {
        //包含了一个和T1同名的方法
        private function sameMethodName(){
            echo "T2.";
        }
    }

    class Foo {

        //同时使用T1和T2两个traits
        use T1,T2 {

            //使用T1中的sameMethodName而不是T2中的

            T1::sameMethodName insteadof T2;

            //将T2中的sameMethodName改名为anotherMethod;
            T2::sameMethodName as public anotherMethod;
        }
    }

    $foo = new Foo();

    $foo->sameMethodName();     //"T1."

    $foo->anotherMethod();      //"T2."

使用Trait实现单例模式

<?php
    trait Singleton {

        protected static $_instance = null;

        final public function getInstance(){
            if (is_null(self::$_instance)){
                self::$_instance = new static();    //延迟静态绑定
            }

            return self::$_instance;
        }

        private function __construct(){
            $this->init();
        }

        protected function init(){}

        final private function __wakeup(){}
        final private function __clone(){}
    }

在类中使用该trait

<?php

    class Foo {

        use Singleton;

        protected function init(){
            echo "iw3c.com";
        }
    }

    $foo1 = Foo::getInstance(); //输出iw3c.com
    $foo2 = Foo::getInstance(); //无输出

总结:

  • 可以使用use引入多个Traits
  • 如果一个类引入了多个Traits,并且Traits中有同名的方法,在没有明确指定如何解决冲突时会产生一个致命错误,需要使用insteadof操作符来指定使用冲突方法中的哪一个方法,也可以使用as操作符将其中一个冲突方法以另一个名称引入。
  • 使用as语法还可以用来调整方法的访问控制权限。
  • Traits 和一个类的形为相似,但是不能被实例化。