trait

peter-yan 2018-02-02 原文

trait

参考

引文

在php中,为实现代码复用,有了继承,但是一个类只能继承一个父类,不支持多继承,接口支持多实现,但是接口又不太一样,接口对外负责功能调用声明,不负责实现,由实现了接口的类去实现具体功能逻辑,严格意义上来说,不算代码复用,从php5.4开始,php实现了另外一种代码复用的方法,就是下文即将要说的trait。

trait

trait是为扩展类似php单继承的一种代码复用机制,解除单继承语言的限制,使开发人员能够自由地在不同层次结构中组合复用method。trait本身不能实例化,它依托于class存在。传统继承是上下层面的关系,trait则为水平层面的组合。

优先级

对于相同方法名的方法而言,当前类的方法覆盖trait方法,trait中方法覆盖继承的父类方法

class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
    
    public function sayPeter() {
        echo "\nhello trait peter\n";
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
    public function sayPeter() {
        echo "\nhello class peter\n";
    }
}

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

输出

 多个trait

在类中,可以声明多个trait,将多个trait组合到一个类中

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}

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

输出

trait冲突

如果trait之间定义了同名的方法,类中又组合了有同名方法的trait,会出现命名冲突,这个时候可以使用insteadof指明调用冲突方法中的某一个。trait中可以用as操作符为某个方法引入别名,注意引入别名并不会对原方法重命名,别名不能和已包含的trait中方法名重复

trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
    public function helloPeter() {
        echo "hello peter\n";
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
    public function helloAlice() {
        echo "hello alice\n";
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class TalkerAs {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}

class TalkerHello {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        // A::helloPeter as helloAlice; 别名不允许和已包含trait中方法重名
    }
}

$talker = new Talker();
$talker->smallTalk();
$talker->bigTalk();
echo "\n";
$talkerAs = new TalkerAs();
$talkerAs->smallTalk();
$talkerAs->bigTalk();
$talkerAs->talk();

输出

trait组合trait

正如class可以使用多个trait,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();

输出

抽象成员方法

在trait中可以定义抽象方法,类中如果要使用trait,必须要实现trait中的抽象方法

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

class MyHelloWorld {
    private $world;
    use Hello;
    public function getWorld() {
        return $this->world;
    }
    public function setWorld($val) {
        $this->world = $val;
    }
}

$o = new MyHelloWorld();
$o->sayHelloWorld();
$o->setWorld('world');
$o->sayHelloWorld();

输出

 属性

trait中也可以定义属性,但要注意trait定了某个属性后,使用该trait的类中就不能定义同样名称的属性,否则会产生fatal error。(属性如果是兼容的(同样的访问控制符和默认值),就不会产生fatal error,但在php7之前,会有E_STRICT提醒)

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

class PropertiesExample {
    use PropertiesTrait;
    public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
    public $different = true; // 致命错误
}

php5.6

php7.1

 

发表于 2018-02-02 15:39 lvp 阅读() 评论() 编辑 收藏

 

版权声明:本文为peter-yan原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/peter-yan/p/8404809.html

trait的更多相关文章

  1. 【原】PHP从入门到精通2小时【图文并茂】

    【原】PHP从入门到精通2小时【图文并茂】 原创内容,转载请注明。 主要内容: 搭建PHP开发环境 第一个he […]...

  2. php安装扩展时报错:make: *** [mbstring.lo] Error 1,解决方案

    php安装扩展时报错:make: *** [mbstring.lo] Error 1,解决方案         […]...

  3. 从源码看 PHP 7 数组的实现

    本文所用源码为 PHP 7.4.4 的版本。 PHP 7 数组概述 PHP 中的数组实际上是一个有序映射。映射 […]...

  4. php基本语法(简略篇)

    简化了很多,算是复习吧 易忽略的细节:指令分隔符 “;” 1)在一些PHP语句的结尾要加上;表示一句话的结束,当然 也不需要可以的去记,因为你一旦漏掉分号,程序根本执行不了,会报错! 2)结束标记 ?> 就隐含了一个 ; 所以在?>之前的...

  5. composer学习总结

    composer 简介:是php用来管理依赖(dependency)关系的工具,工具包地址:https://p […]...

  6. PHP 判断是否包含某字符串

    PHP判断字符串的包含,可以使用PHP的内置函数 strstr,strpos,stristr直接进行判断.也可以通过explode函数的作用写一个判断函数。下面介绍PHP判断字符串的包含的具体使 用方法:1. strstr: 返回一个从被...

  7. 使用PHP导出数据到CSV文件

    使用PHP导出数据到CSV文件 CSV,是Comma Separated Value(逗号分隔值)的英文缩写, […]...

  8. PHP 基础

    php 基础知识php 简介php 被译为个人主页:超文本预处理器。它是一种运行在服务器端的脚本语言,必须在服务器环境下才能运行。php 运行环境配置搭建方式一键搭建手动搭建修改 php 配置文件(php.ini)将时区修改为系统时区...

随机推荐

  1. 【Unity笔记】Awake()和Start()的区别

    Awake在MonoBehavior创建后就立刻调用,Start将在MonoBehavior创建后在该帧Upd […]...

  2. EXCEL表中如何让数值变成万元或亿元

    EXCEL表中如何让数值变成万元或亿元 | 浏览:543 | 更新:2013-12-05 12:48 | 标签 […]...

  3. 【转】Mac不能复制拷贝写入文件到移动硬盘,U盘怎么办 | – wi100sh

    【转】Mac不能复制拷贝写入文件到移动硬盘,U盘怎么办 | 原文网址:http://jingyan.baidu […]...

  4. koa源码阅读[3]-koa-send与它的衍生(static)

    koa源码阅读的第四篇,涉及到向接口请求方提供文件数据。 第一篇:koa源码阅读-0第二篇:koa源码阅读-1 […]...

  5. 贪心算法(Greedy Algorithm):最优装载问题(python)

     **利用贪心算法求解的问题具有两个特性:     1.贪心选择策略:指原问题的最优解可以通过一系列局部最优得 […]...

  6. Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理

    为什么使用消息队列 其实就是问问你消息队列都有哪些使用场景,然后你项目里具体是什么场景,说说你在这个场景里用消 […]...

  7. xtraReports 报表横向打印

    设置属性 landscape = true...

  8. Ajax

    什么是同步异步? 同步:客户端发送请求到服务器端,当服务器返回响应之前,客户端都处于等待 卡死状态,比如当我百 […]...

展开目录

目录导航