php关键字-trait

举报
仙士可 发表于 2023/06/14 11:38:58 2023/06/14
【摘要】 介绍自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。Trait 和 Class...

介绍

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

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

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

<?php
trait Hello{
    public function echo_hello(){
        echo 'hello';
    }
}
trait World{
    public function echo_world(){
        echo 'world';
    }
}

class A{
    use Hello,World;
}
$a = new A();
$a->echo_hello();
$a->echo_world();
复制

输出:

trait的应用场景

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

Trait就是为了解决这种问题而诞生的。Trait能够把模块化的实现方式注入多个无关的类中,从而提高代码复用,符合DRY(Don’t Repeat Yourself) 原则和面对对象单一职责。

使用场景一:

<?php
trait Login{
    public function login(){
    }
}
trait Register{
    public function register(){
    }
}

class Auth{
    use Login,Register;
    public function auth(){
        
    }
}
$a = new Auth();
复制

当系统底层的auth验证时,auth类通过use login,use register,使底层验证类有了登录注册功能,实现了代码复用

使用场景二:

trait Singleton{
    protected static $_instance;
    public static function getInstance()
    {
        if(! (self::$_instance instanceof self) )
        {
            self::$_instance = new static(); //new static和new self区别可查看http://www.jb51.net/article/54167.htm
        }
        return self::$_instance;
    }
}
class A{
    use Singleton;

}
class B{
    use Singleton;

}

$a = A::getInstance();
$b = B::getInstance();
var_dump($a);
var_dump($b);
复制

用trait实现单例模式

trait优先级

一:方法优先级

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

trait Test{
    public function echo_a(){
        echo 'test_a';
    }
}
class A{
    use Test;
    public function echo_a(){
        echo 'a';
    }
}
$a = new A();
$a->echo_a();
复制

输出 'a';

trait Test{
    public function echo_a(){
        echo 'test_a';
    }
}
class BaseA{
    public function echo_a(){
        echo 'base_a';
    }
}
class A extends BaseA {
    use Test;
}
$a = new A();
$a->echo_a();
复制

输出 'test_a';

二:属性优先级

在 PHP 7.0 之前,在类里定义和 trait 同名的属性,哪怕是完全兼容的也会抛出 E_STRICT(完全兼容的意思:具有相同的访问可见性、初始默认值)。

7.0之后,完全相同的属性,不会抛出错误

<?php
trait Test{
    public $a = 2;
    static $b=1;
}
class A {
    public $a = 2;
    use Test;
}
class B {
    static $b = 1;
    use Test;
}
$a = new A();
echo $a->a;
echo "<br>";
echo B::$b;
复制

输出:

多个trait冲突

使用逗号,可以use 多个trait;

如果use多个方法名相同的trait并且没做任何处理的话,将会产生一个致命错误

<?php
trait Test1{
    public function echo_a(){
        echo 'test1_a';
    }
}
trait Test2{
    public function echo_a(){
        echo 'test2_a';
    }
}
class A  {
    use Test1,Test2;
}
$a = new A();
$a->echo_a();
复制

    解决方法:需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。

<?php
trait Test1{
    public function echo_a(){
        echo 'test1_a';
    }
    public function echo_b(){
        echo 'test1_b';
    }
}
trait Test2{
    public function echo_a(){
        echo 'test2_a';
    }
    public function echo_b(){
        echo 'test2_b';
    }
}
class A  {
    use Test1,Test2{
      Test2::echo_a insteadof Test1;
      Test1::echo_b insteadof Test2;
    }
}
$a = new A();
$a->echo_a();
echo "\n";
$a->echo_b();
复制

输出:

as操作符

一:当多个trait冲突,使用insteadof排除其中一个时,可使用as操作符赋予别名进行调用

<?php
trait Test1{
    public function echo_a(){
        echo 'test1_a';
    }
    public function echo_b(){
        echo 'test1_b';
    }
}
trait Test2{
    public function echo_a(){
        echo 'test2_a';
    }
    public function echo_b(){
        echo 'test2_b';
    }
}
class A  {
    use Test1,Test2{
      Test2::echo_a insteadof Test1;
      Test1::echo_b insteadof Test2;
      Test2::echo_b as echo_b_2;//赋予别名
    }
}
$a = new A();
$a->echo_a();
echo "\n";
$a->echo_b();
echo "\n";
$a->echo_b_2();
复制

输出:

二:使用as操作符修改访问权限

class A {
    public $a = 1;

    use Test{
        Test::echo_a as private;
    }

    public function want_echo_a(){
        $this->echo_a();
    }
}
$a = new A();
//$a->echo_a();//直接调用将会报错
$a->want_echo_a();
复制

输出结果:

Trait 的抽象成员,

<?php
trait Test{
    public function __construct()
    {
        $this->echo_test();
    }

    abstract function echo_test();//
}
class A {
    public $a = 2;
    use Test;
    public function echo_test()
    {
        echo '1';
    }
}
$a = new A();
复制

输出:

Trait的静态成员

<?php
trait Test{
    public function echo_test()
    {
        static $a=1;
        $a++;
        echo $a;
    }

}
class A {
    use Test;
}
class B {
    use Test;
}
$a = new A();
$b = new B();
$a->echo_test();
echo "\n";
$a->echo_test();
echo "\n";
$b->echo_test();
echo "\n";
$b->echo_test();
复制

输出

静态成员基本和http://www.php20.cn/article/sw/%E9%9D%99%E6%80%81/55 说明一致

以上就是关于trait的说明以及用法了

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。