PHP中trait的特性

转载链接:https://www.jb51.net/article/105579.htm

1.trait简介

1.1 特性

(1)优先级:当前类中的方法 > trait中的方法 > 基类中的方法
(2)多个trait使用,分隔
(3)trait 冲突使用insteadof操作符号来指定使用冲突方法中的哪一个
(4)as操作符可以为方法设置别名,也可以修改trait中的方法的访问控制
(5)其他trait也可以使用trait。
(6)Traits 可以被静态成员静态方法定义。
(7)在引用Trait时,使用了use关键字,use关键字也用来引用命名空间。两者的区别在于,引用Trait时是在class内部使用的。比如thinkphp5框架中use concern\ModelRelationQuery;
(8)Trait 定义了一个属性后,类就不能定义同样名称的属性(名字,值和访问控制相同就没问题),否则会产生 fatal error。

1.2 优点

解决代码复用,解决PHP单继承的问题;

1.3 区别

trait和class的区别是trait不能被实例化

1.4 代码
<?php


class Base{
//    public function sayHello(){
//        echo "hello";
//    }
}

trait Mood{
    public $a =1;
    public function sayMood()
    {
        echo "!";
    }
}

trait Sayworld{

    public function sayHello()
    {

//        parent::sayHello();
        echo "world";
    }
    abstract public function getWorld();

    public static function doSomething()
    {
        echo "static function";
    }
}

class MyHelloWorld extends Base{

    use Sayworld,Mood{
        sayHello as public;
    }

    public $a =1 ; //=2值不同就会fatal error



    public function getWorld()
    {

        return "getWorld";
    }
//    public function sayHello()
//    {
        parent::sayHello();
//        echo "MyHelloWorld";
//    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayMood();
$o::doSomething();
trait Man{
    use Sayworld;
    public function eat()
    {
        echo "man word";
    }
    public function talk(){
        echo "Chinese";
    }

    public function inc()
    {
        static $i=1;
        $i++;
        echo $i;
    }

}

trait Woman{
    public function eat()
    {
        echo "woman home";
    }

    public function talk()
    {
        echo "English";
    }
}

class Person{
    use Man,Woman{
     Woman::eat insteadof Man;
     Man::talk insteadof Woman;
     Woman::talk as talks;

    }

    public function getWorld()
    {
        // TODO: Implement getWorld() method.
    }

}
class Animals{
    use Man;
    public function getWorld()
    {
        // TODO: Implement getWorld() method.
    }
}
$person = new Person();
//$person->eat();
//$person->talks();
//$person->sayHello();
$person->inc();
(new Animals())->inc();  //静态变量不会改变  都是2

2.使用场景

熟悉面向对象的都知道,软件开发中常用的代码复用有继承和多态两种方式。在PHP中,只能实现单继承。而Trait则避免了这点。下面通过简单的额例子来进行对比说明。

  1. 继承 VS 多态 VS Trait
    现在有Publish.php和Answer.php这两个类。要在其中添加LOG功能,记录类内部的动作。有以下几种方案:
    继承
    多态
    Trait
2.1. 继承

如图:
在这里插入图片描述

代码结构如下:
// Log.php

<?php
Class Log
{
 public function startLog()
 {
  // echo ...
 }
 
 public function endLog()
 {
  // echo ...
 }
} 

// Publish.php

<?php
Class Publish extends Log
{
 
}

// Answer.php

<?php
Class Answer extends Log
{

} 

可以看到继承的确满足了要求。但这却违背了面向对象的原则。而发布(Publish)和回答(Answer)这样的操作和日志(Log)之间的关系并不是子类与父类的关系。所以不推荐这样使用。

2.2. 多态

如图:
在这里插入图片描述
// Log.php

<?php
Interface Log
{
 public function startLog();
 public function endLog();
}

// Publish.php

<?php
Class Publish implements Log
{
 public function startLog()
 {
  // TODO: Implement startLog() method.
 }
 public function endLog()
 {
  // TODO: Implement endLog() method.
 }
}

// Answer.php

<?php
Class Answer implements Log
{
 public function startLog()
 {
  // TODO: Implement startLog() method.
 }
 public function endLog()
 {
  // TODO: Implement endLog() method.
 }
} 

记录日志的操作应该都是一样的,因此,发布(Publish)和回答(Answer)动作中的日志记录实现也是一样的。很明显,这违背了DRY(Don’t Repeat Yourself)原则。所以是不推荐这样实现的。

2.3. Trait

如图:
在这里插入图片描述
// Log.php

<?php
trait Log{
 public function startLog() {
  // echo ..
 }
 public function endLog() {
  // echo ..
 }
}

// Publish.php

<?php
class Publish {
 use Log;
}
$publish = new Publish();
$publish->startLog();
$publish->endLog();

// Answer.php

<?php
class Answer {
 use Log;
}
$answer = new Answer();
$answer->startLog();
$answer->endLog(); 

可以看到,我们在没有增加代码复杂的情况下,实现了代码的复用。

2.4. 结论

继承的方式虽然也能解决问题,但其思路违背了面向对象的原则,显得很粗暴;多态方式也可行,但不符合软件开发中的DRY原则,增加了维护成本。而Trait方式则避免了上述的不足之处,相对优雅的实现了代码的复用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值