谈谈PHP中的trait

本文深入探讨PHP中的Trait特性,解释其出现的原因、目的及应用场景。并详细解析Trait的基础使用、方法冲突解决策略以及如何通过权限调整来增强代码的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

PHP因为其单继承的特性,无法满足继承多个文件的情况下,在php 5.4版本出现了trait 。use 了某个trait 使用trait中的方法就像是调用自己的方法一样简便。在 trait 中定义基础的方法,方便其他类直接调用。
声明一个 trait 需要使用关键字 trait 调用它需要使用 use,且它无法被实例化。

目的

它存在的目的是为了减少代码的重复性,提高代码的复用性。

应用场景

当有些基础方法使用率比较高,或者是一种规则的定义需要我们统一计算,但他们不是每个类都需要用到时,我们可以考虑将它放入 trait 中。
假如一个类继承了基础类,这个类代码的大小其实是自己的代码大小加上基础类代码量的大小,所有基础类里面我们尽量定义那种每个类中都会用到的方法,并尽量保持基础类文件简洁。
它不仅仅是可复用代码段的集合,它应该是一组描述了某个特性的的属性与方法的集合。它的优点在于随意组合,耦合性低,可读性高

简单使用

1. 基础代码

trait dog{
    public function eat(){
        echo '狗吃狗粮</br>';
    }
}

trait cat{
    public function eat(){
        echo '猫吃猫粮</br>';
    }
}

class animal{
    public function eat(){
        echo '请问动物吃什么</br>';
    }
}

class whatEat extends animal {
    public function questios(){
        echo '发起提问</br>';
    }
}

$whatEat = new whatEat();
$whatEat->questios();
$whatEat->eat();

返回结果
在这里插入图片描述

此处只继承了基础类 animal 所以调用eat返回的是 ‘请问动物吃什么’

2. 调用其中一个trait中的方法

class whatEat extends animal {
    use cat;
    public function questios(){
        echo '发起提问</br>';
    }
}

$whatEat = new whatEat();
$whatEat->questios();
$whatEat->eat();

得到结果:
在这里插入图片描述

结论:我们很明显看出来 基础类animal中的eat直接被 cat中的eat覆盖掉了

3. 在自己的方法中定义一个和trait中同名的方法

class whatEat extends animal {
    use cat;
    public function questios(){
        echo '发起提问</br>';
    }

    public function eat(){
        echo '各个动物吃的东西都不同';
    }
}

$whatEat = new whatEat();
$whatEat->questios();
$whatEat->eat();

得到结果:
在这里插入图片描述

结论:从上面我们知道 基础类animal 和whatEat自身,trait cat都拥有一个同名的方法 但是通过 【3】 我们知道了优先级最高的是类本身的方法。通过【2】我们知道了 基础类和trait 拥有同名方法,优先级最高的是trait内的方法。
所有 优先级是 类本身内的方法 > trait中的方法 > 基础类的方法

4. 若是我们在类中同时引用两个 trait ,且这两个trait都拥有一个同名方法呢?

class whatEat extends animal {
    use cat;
    use dog;
    public function questios(){
        echo '发起提问</br>';
    }
}

$whatEat = new whatEat();
$whatEat->questios();
$whatEat->eat();

返回结果:
在这里插入图片描述

结论:直接报 500 。所有同时引进的 trait 中有同名方法会直接导致类报错。因为不同trait中存在同名方法会存在冲突。
那我们如何处理这种错误呢。解决方法有两个

4.1. 冲突解决方法一,使用 insteadof 替换

class whatEat extends animal {
    use cat,dog{
        dog::eat insteadof cat;
        cat::eat as cateat;
    }

    public function questios(){
        echo '发起提问</br>';
    }
}

$whatEat = new whatEat();
$whatEat->questios();
$whatEat->eat();
$whatEat->cateat();

返回结果:
在这里插入图片描述

结论:cat 中的方法直接被 dog 中的替换掉了。调用类中的 eat 直接返回的是 dog 中的 eat ,而 cat 中的 eat 被重新命名为 cateat 使用

4.2 冲突解决方法二 使用优先级的特性 让类的同名文件将其覆盖掉

class whatEat extends animal {
    use cat,dog;
    public function questios(){
        echo '发起提问</br>';
    }

    public function eat(){
        cat::eat();
    }

    public function eat2Dog(){
        dog::eat();
    }
}

$whatEat = new whatEat();
$whatEat->questios();
$whatEat->eat();
$whatEat->eat2Dog();

返回结果:
在这里插入图片描述

结论:将trait中的方法通过 优先级别将其覆盖掉。在定义一个别名方法将被覆盖掉了的方法重新实现出来。

5. as取别名后 原来的方法名依旧能使用

class whatEat extends animal {
    use cat{
        cat::eat  as cateat;
    }

    public function questios(){
        echo '发起提问</br>';
    }


}

$whatEat = new whatEat();
$whatEat->questios();
$whatEat->eat();
$whatEat->cateat();

返回结果:
在这里插入图片描述

结论:不论是使用 eat 这个原本的名字 还是使用在类中重命名之后的 cateat 都得到了返回结果 ‘猫吃猫粮’

6. 进阶知识

as除了可以用来取别名之外 还可以给方法定义权限 

6.1 公有的转为私有的

class whatEat extends animal {
    use cat{
        cat::eat  as private cateat;
    }

    public function questios(){
        echo '发起提问</br>';
    }


}

$whatEat = new whatEat();
$whatEat->questios();
echo 'eat 返回的结果:';
$whatEat->eat();
echo '</br>';

echo 'private cateat返回的结果:';
$whatEat->cateat();
echo '</br>';

返回结果:
在这里插入图片描述

结论:返回未报错,方法 eat 被正常调用 但是被定义为 private 的 cateat 并没有返回结果。同样测试protected 也没有得到结果 只有定义为public 时候才返回出结果。

6.2 私有的变为公有的

trait cat{
    public function eat(){
        echo '猫吃猫粮</br>';
    }
    protected function eat2(){
        echo '猫也吃小鱼干</br>';
    }
}

class animal{
    public function eat(){
        echo '请问动物吃什么</br>';
    }

}

class whatEat extends animal {
    use cat{
        cat::eat2 as public eat22;
    }

    public function questios(){
        echo '发起提问</br>';
    }
}
$whatEat = new whatEat();
$whatEat->questios();
echo 'eat2 返回的结果:';

返回结果
在这里插入图片描述
在看 取别名为 eat22 返回的结果

$whatEat = new whatEat();
$whatEat->questios();
echo 'eat22 返回的结果:';
$whatEat->eat22();

在这里插入图片描述

结论: 原本 trait 文件中权限为 protected 的方法 在class里面被重新定义了 权限和命名后,变为了公有方法,可以直接在外部调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值