2.6PHP语言的Trait

1.Trait声明

trait trait名 {
    //trait体
}

trait 体中可以包含静态变量、静态属性、静态方法、类常量、实例属性、实例方法。

trait 体中还可以含有 abstract 抽象方法,一个具体类 use 使用这个 trait 时必须实现这个抽象方法。抽象方法支持可见性修饰符 publicprotectedprivate

trait 不可以继承,也不可以实例化。

2.use使用trait

2.1类use使用trait

//同一个trait被多个类use使用
class 类名1 {
    use trait名;
}

class 类名2 {
    use trait名;
}
//同一个类use使用多个trait
class 类名 {
    use trait名1, trait名2;
}

2.2trait use使用trait

正如类能够 use 使用 trait 一样,trait 也能够 use 使用其它 trait中的部分或全部成员。

//同一个trait被多个trait use使用
trait trait名1 {
    use trait名3;
}

trait trait名2 {
    use trait名3;
}
//同一个trait use使用多个trait
trait trait名3 {
    use trait名1, trait名2;
}

3.访问trait中的成员

trait 中的成员访问步骤:首先通过类 use 使用 trait,然后按照正常的类的成员的调用方式调用,不可以通过 trait 自身直接调用。

4.名称冲突

4.1常量名称冲突

当类中的常量 与 trait 中的常量名称相同时,类中的常量必须与 trait 中的常量具有相同的 final、可见性、初始化值,否则会抛出 fatal error。

trait ConstantsTrait {
    public const FLAG_MUTABLE = 1;
    final public const FLAG_IMMUTABLE = 5;
}

class ConstantsExample {
    use ConstantsTrait;
    public const FLAG_IMMUTABLE = 5; // Fatal error

4.2实例属性名称冲突

当类中的属性 与 trait 中的属性名称相同时,类中的属性必须与 trait 中的属性具有相同的 可见性、readonly、类型、初始化值,否则会抛出 fatal error。

trait PropertiesTrait {
    public $same = true;
    public $different1 = false;
    public bool $different2;
    public bool $different3;
}

class PropertiesExample {
    use PropertiesTrait;
    public $same = true;
    public $different1 = true; // Fatal error
    public string $different2; // Fatal error
    readonly protected bool $different3; // Fatal error
}

4.3实例方法名称冲突

当子类中的方法、trait中的方法、父类中的方法名称相同时,则覆盖规则为:子类中的方法会覆盖 trait 中的方法,而 trait 中的方法则会覆盖父类中的方法。

//子类中的方法会覆盖trait中的方法
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello();

//输出
Hello Universe!
//trait中的方法会覆盖父类中的方法
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();

//输出
Hello World!

当同一个类 use 多个 trait 但多个 trait 有同名方法时,可使用 insteadof 运算符 或 as 运算符两种方式解决命名冲突。

注意:as 运算符可以为方法添加别名或更改可见性,但不会更改原有方法的名称和可见性。

trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    use A, B {
        //B中的smallTalk()方法代替A中的smallTalk()方法
        B::smallTalk insteadof A;
        //A中的bigTalk()方法代替B中的bigTalk()方法
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        //为B中的bigTalk()方法添加talk别名
        B::bigTalk as talk;
    }
}
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

//更改可见性
class MyClass1 {
    use HelloWorld { sayHello as protected; }
}

//添加别名和更改可见性
class MyClass2 {
    use HelloWorld { sayHello as private myPrivateHello; }

原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/php/phplang/28895.html

(0)
上一篇 2023年7月5日
下一篇 2023年7月7日

相关推荐

  • 2.10PHP语言的特性(Attribute)类

    1.特性(Attribute)类声明 声明一个特性类,首先从全局命名空间 use 导入 #[Attribute] 特性,然后在普通类声明上添加 #[Attribute] 特性以表示此类为特性类。 特性目标 描述 Attribute::TARGET_ALL 不限制用于具体哪一个。 Attribute::TARGET_CL…

    PHP语言教程 2023年7月10日
    0200
  • 2.9PHP语言的生成器(Generator)类

    1.生成器函数声明 生成器函数声明就跟普通函数声明一样,区别在于:生成器函数体必须至少包含一个 yield,可包含也可不包含 return。 yield 与 return 的区别在于:return 会立即终止函数的执行并返回值,而 yield 会向在生成器(Generator)类的对象上迭代的代码提供一个值,并暂停生成…

    PHP语言教程 2023年7月9日
    0180
  • 1.4PHP语言的运算符(Operator)和非运算符(Non-Operator)

    1.一元运算符 运算符 名称 描述 +$a 取正 根据情况将 $a 转化为 int 或 float。 -$a 取反 $a 的负值。 ++$a 前递增 $a 的值加 1,然后返回 $a。 –$a 前递减 $a 的值减 1, 然后返…

    PHP语言教程 2023年6月4日
    0420

发表回复

登录后才能评论