资讯专栏INFORMATION COLUMN

【modernPHP专题(5)】类多继承的替代方案Traits

imtianx / 469人阅读

摘要:概述是新进入的特性,其目的就是解决的类不能多继承的问题。可以理解为一组能被不同的类都能调用到的方法集合。只需要在类中使用关键词引入即可,可引入多个,用隔开。为了解决多个在同一个类中的命名冲突,需要使用操作符来明确指定使用冲突方法中的哪一个。

概述

traits是PHP5.4新进入的特性,其目的就是解决PHP的类不能多继承的问题。Traits不是类!不能被实例化。可以理解为一组能被不同的类都能调用到的方法集合。只需要在类中使用关键词use引入即可,可引入多个Traits,用","隔开。

简单使用
trait myTrait{

    public $traitPublic = "public";
    protected $traitProtected = "protected";

    function traitMethod1()
    {
        echo __METHOD__,PHP_EOL;
    }

    function traitMethod2()
    {
        echo __METHOD__,PHP_EOL;
    }
}

class myClass{
    use myTrait;
}

$obj = new myClass();
$obj->traitMethod1();
$obj->traitMethod2();

// ↓↓ 只能调用public的属性和方法; protected以及private只供在traits内部自己调用;
echo $obj->traitPublic;
优先级问题

Trait会覆盖继承的方法,当前类会覆盖Trait方法。即 继承的方法 < Traits方法 < 当前类方法,

trait A{
    public $var1 = "test";

    public function test()
    {
        echo "A::test()";
    }

    public function test1()
    {
        echo "A::test1()";
    }
}

class B{
    public function test()
    {
        echo "B::test()";
    }

    public function test1()
    {
        echo "B::test1()";
    }
}

class C extends B{
    use A;

    public function test()
    {
        echo "c::test()";
    }
}

$c = new C();
$c->test(); //c::test() Traits方法 < 当前类方法
$c->test1(); //A::test1() 继承的方法 < Traits方法
多个Trait冲突问题

如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。

为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。

可用as操作符将其中一个冲突方法另起名;

trait A{
    public function test()
    {
        echo "A::test()";
    }
}

trait B{
    public function test()
    {
        echo "B::test()";
    }
}

class C{
    use A , B {
        B::test insteadof A; //明确B替代A
        B::test as t; //或者另起一个名字
    }
}

$c = new C();
$c->test(); //B::test()
$c->t(); //B::test()   可以用as另起名
as可用来修改方法访问控制
trait  HelloWorld{
    public function sayHello()
    {
        echo "Hello World!";
    }
}

// 修改 sayHello 的访问控制
class  A{
    use  HelloWorld {
        sayHello as protected;
    }
}

// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化
class  B{
    use  HelloWorld {
        sayHello as private myPrivateHello;
    }
}

$a = new A();
$a->sayHello(); //Fatal error: Call to protected method A::sayHello() from context ""; 改变了sayHello的访问规则;

$b = new B();
$b->sayHello(); //Hello World!
Trait中使用Trait
trait Hello{
    public function sayHello()
    {
        echo "Hello ";
    }
}

trait World{
    public function sayWorld()
    {
        echo "World!";
    }
}

trait HelloWorld{
    use Hello , World;
}

class MyHelloWorld{
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld(); // Hello World!
Trait中抽象成员

为了对使用的类施加强制要求,trait 支持抽象方法的使用。

trait Hello{
    public function sayHelloWorld()
    {
        echo "Hello" . $this->getWorld();
    }

    abstract public function getWorld();
}

class MyHelloWorld{
    private $world;
    use Hello;

    // 必须要实现trait里面的抽象方法,否则Fatal error: Class MyHelloWorld contains 1 abstract method and must therefore be declared abstract or implement the remaining methods
    public function getWorld()
    {
        return $this->world;
    }

    public function setWorld($val)
    {
        $this->world = $val;
    }
}

$obj = new MyHelloWorld();
echo $obj->setWorld();
Trait中静态成员

Traits 可以被静态成员静态方法定义,不可以直接定义静态变量,但静态变量可被trait方法引用.

# 静态属性;
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c + 1;
        echo "$c
";
    }
}

class C1 {
    use Counter;
}

class C2 {
    use Counter;
}

$o = new C1();
$o->inc(); // echo 1
$o->inc(); // echo 2;

$p = new C2();
$p->inc(); // echo 1

# 静态方法
trait StaticExample {
    public static function doSomething() {
        echo "Doing something";
    }
}

class Example {
    use StaticExample;
}

Example::doSomething(); // Doing something
Trait中属性
trait PropertiesTrait{
    public $x = 1;
}

class PropertiesExample{
    use PropertiesTrait;
}

$example = new PropertiesExample;
echo $example->x; // 1

如果 trait 定义了一个属性,那类将不能定义同样名称的属性,否则会产生一个错误。如果该属性在类中的定义与在 trait 中的定义兼容(同样的可见性和初始值)则错误的级别是 E_STRICT,否则是一个致命错误。

trait PropertiesTrait {
    public $same = true;
    public $different = false;
}

class PropertiesExample {
    use PropertiesTrait;
    public $same = true; // Strict Standards
    public $different = true; // 致命错误
}

参考链接:

http://www.php.net/manual/zh/...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31373.html

相关文章

  • modernPHP专题(4)】抽象类与接口

    摘要:抽象类支持抽象类和抽象方法。接口是一种特殊的抽象类,这种抽象类中只包含抽象方法和静态常量。对抽象类的使用是通过关键字。抽象类中可以声明各种类型成员变量,实现数据的封装。一个类可以同时实现多个接口,但一个类只能继承于一个抽象类。 抽象类 php5支持抽象类和抽象方法。类前加 abstract, 此类就成为抽象类,无法被实例化,此类天生就是用来被继承的,给子类提供了一个类的模板;类方法前加...

    Keven 评论0 收藏0
  • modernPHP专题(2)】反射机制Reflection

    摘要:简介是才有的新功能,它是用来导出或提取出关于类方法属性参数等的详细信息,包括注释。 简介 PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。 class Reflection { } interface Reflector { } class ReflectionException extends Exce...

    mrli2016 评论0 收藏0
  • modernPHP专题(9)】匿名类

    摘要:复制当前闭包对象,绑定指定的对象和类作用域。类作用域,可以是对象,也可以是实例名称什么是匿名类先理解以下三个例子例闭包函数都是继承类返回匿名函数返回匿名函数,也就是闭包函数,所有闭包函数都是继承类输出例将一个匿名函数绑定到一个类中。 类结构 Closure { /* 方法 */ // 用于禁止实例化的构造函数 __construct ( void ) ...

    ninefive 评论0 收藏0
  • modernPHP专题(3)】依赖注入与服务容器

    摘要:而依赖倒置原则的思想是,上层不应该依赖下层,应依赖接口。上面通过构造函数注入对象的方式,就是最简单的依赖注入当然注入不仅可以通过构造函数注入,也可以通过属性注入,上面你可以通过一个来动态为这个属性赋值。 依赖倒置和控制反转是一种编程思想,而依赖注入就是通过服务容器实现这种面向接口或者是面向抽象编程的思想 概念理解 依赖倒置原则 依赖倒置是一种软件设计思想,在传统软件中,上层代码依赖于下...

    terro 评论0 收藏0
  • modernPHP专题(1)】php7常用特性整理

    摘要:它使得在生产环境中启用断言为零成本,并且提供当断言失败时抛出特定异常的能力。错误和异常改变了大多数错误的报告方式。不同于传统的错误报告机制,现在大多数错误被作为异常抛出。 PHP7性能 7最大的亮点,应该就是性能提高了两倍,某些测试环境下甚至提高到三到五倍,具体可以了解以下链接: PHP7 VS HHVM (WordPress) HHVM vs PHP 7 – The Competit...

    Render 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<