PHP 面向对象高级:Trait 1 个改进

PHP Trait

Trait 是 PHP 5.4引入的新概念,看上去既像类又像接口,其实都不是,Trait 可以看做类的部分实现,可以混入一个或多个现有的 PHP 类中,其作用有两个:表明类可以做什么;提供模块化实现。Trait是一种代码复用技术,为 PHP 的单继承限制提供了一套灵活的代码复用机制。

为什么使用Trait

PHP 语言使用一种典型的单继承模型,在这种模型中,我们先编写一个通用的根类,实现基本的功能,然后扩展这个根类,创建更具体的子类,直接从父类继承实现。这叫做继承层次结构,很多编程语言都使用这个模式。大多数时候这种典型的继承模型能够良好运作,但是如果想让两个无关的 PHP 类具有类似的行为,应该怎么做呢?Trait 就是为了解决这种问题而诞生的。

如何使用Trait

用法

Trait 的使用方法也很简单,下面有说明的例子,即使用 use 关键字。

可能你已经注意到,命名空间(namespace) 和 Trait 使用的都是 use 关键字,不同之处在于导入位置,命名空间在类的定义体外导入,而 Trait 在类的定义体内导入。

例子

trait Drive {
    public $carName = 'trait';
    public function driving() 
    {
      echo "driving {$this->carName}\n";
    }
  }
  class Person {
    public function eat() 
    {
      echo "eat\n";
    }
  }
  class Student extends Person {
    //使用Trait  
    use Drive;
    public function study() 
    {
      echo "study\n";
    }
  }
$student = new Student();
$student->study();
$student->eat();
$student->driving();

输出结果如下:

study
eat
driving trait    

上面的例子中,Student 类通过继承 Person ,有了 eat 方法,通过组合 Drive,有了driving 方法和属性 carName。

问题

能否引入多个 Trait,如果可以,如何引入;同名方法如何处理

Trait 可以引入多个,使用逗号分隔即可

use Trait1,Trait2;
trait method1{
    //定义方法
    function add()
    {
        echo "This is add action".PHP_EOL;
    }
}

trait method2{
    //定义方法
    function add()
    {
        echo "This is add action".PHP_EOL;
    }
}

class Article{
    //引入多个trait
    use method1,method2;
}

$article = new Article();
$article->add();

输出结果

PHP Fatal error:  Trait method add has not been applied, because there are collisions with other trait methods on Article.
Fatal error: Trait method add has not been applied, because there are collisions with other trait methods on Article

上面的报错是因为多个 trait 中存在同名方法

如果多个 trait 中存在同名方法,可以使用 insteadofas 操作符来解决问题, insteadof是使用某个方法替代另一个方法,而 as 是给方法取一个别名 。

trait method1{
    //定义方法
    function add()
    {
        echo "This is add action of method1".PHP_EOL;
    }
}

trait method2{
    //定义方法
    function add()
    {
        echo "This is add action of method2".PHP_EOL;
    }
}

class Article{
    use method1,method2{
        //指定使用method2中的add方法,解决method1中同名方法冲突
        //若同名方法存在多个,insteadof 后可跟多个,用逗号隔开
        method2::add insteadof method1;
        //给method1中的add方法取别名
        method1::add as addArticle;
    }

}

$article = new Article();
// 调用method2中的add方法
$article->add();
// 调用method1中的add方法
$article->addArticle();

输出结果

This is add action of method2
This is add action of method1

Trait 引入方法与现有方法重名时,如何解决

trait 引入方法与现有方法重名时,会优先调用类中已定义的方法,其优先级顺序为: 当前类方法>trait方法>父类方法

能否对方法进行权限控制

可以进行方法权限控制

trait method1{
    //定义私有方法
    private function delete()
    {
        echo "This si delete action" . PHP_EOL;
    }
    //定义受保护的方法
    protected function add()
    {
        echo "This is add action of method1" . PHP_EOL;
    }
    //定义公共方法
    public function index()
    {
        echo "This is index action" . PHP_EOL;
    }
}
本文为 Wiki 文章,邀您参与纠错、纰漏和优化
讨论数量: 1

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!