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. [极客大挑战 2019]PHP

    [极客大挑战 2019]PHP 打开靶场,敏感的人可能已经发现重点了。 扫描一下备份文件,扫出来了 下载到本地看看里面有什么信息,发现三个重要的php文件源码,看了一下,这题是 php反序列化 。 # index.php...<?phpi...

  2. Yii2设计模式——静态工厂模式

    应用举例 yii\db\ActiveRecord //获取 Connection 实例 public stat […]...

  3. php 的开发工具

    通过上篇我们已经配置好了php的开发环境,我们就可以在这个模拟的环境下运行我们编写的php代码了。 在编写代码 […]...

  4. php 发邮件的2种方式(使用stmp类、使用socket协议)

    方式1:使用stmp类发送邮件 代码: stmp.php 1 <?php 2 header("Conte […]...

  5. 数据库状态标识位flag设计

    设计目的 减少各种状态值字段 减少数据库冗余和存储空间 增加状态值时可灵活调整,无需增加额外字段 运用场景 例 […]...

  6. PHP 制作通讯录(一) – zimmerk

    PHP 制作通讯录(一) 最近在学PHP ,觉得比较简单,可能是因为有一点编程经验的缘故吧,今天教大家用PHP […]...

  7. PHP xdebug + PhpStorm调试远程服务器代码

    1.服务器(linux centos)安装xdebug pecl install xdebug 注意看安装完成 […]...

  8. php图片上传代码

    php图片上传代码本来是一个很简单的事,之前笔者图省事,直接网上下载了一个php图片上传小程序,结果导致wordpress网站被黑,因为留有后门,后来排查直接删除整个小程序,自己用重新写了一个php图片上传功能,缺点就是只能单张上传!简...

随机推荐

  1. 使用 JavaScript 将 HTML 转换为 PDF

    使用 JavaScript 将 HTML 转换为 PDF 更多相关学习资料参见http://www.pdfdo […]...

  2. 怎么用光功率计测试两台光端机间的传输距离

    选择对应光端机的发射波长,先在本端测试其中一台光端机的发光功率,然后再到对端测试通过光纤以后的光功率,因为都是 […]...

  3. 网页如何播放视频

    网页当中播放视频有3种实现方式: 1.使用html5的<video>…</vid […]...

  4. Windows下安装mysql的操作步骤 – Heart丶Beat

    免安装版的Mysql  MySQL关是一种关系数据库管理系统,所使用的 SQL 语言是用于访问数据库的最常用的 […]...

  5. org.mybatis.spring.MyBatisSystemException异常及处理

    org.mybatis.spring.MyBatisSystemException异常处理 测试场景 在测试s […]...

  6. MongoDB4.2 副本集扫盲说明

      在扫盲MongoDB相关的一些知识的时候,顺手做下笔记。本文将说明副本集相关的内容。在比较早之前已经对这些 […]...

  7. IOS – OpenGL ES 图像漩涡 GPUImageSwirlFilter

    目录一.简介二.效果演示三.源码下载四.猜你喜欢零基础 OpenGL (ES) 学习路线推荐 : OpenGL (ES) 学习目录 >> OpenGL ES 基础零基础 OpenGL (ES) 学习路线推荐 : OpenGL (E...

  8. Laya 踩坑日记 —A* 导航寻路

    要做寻路,然后看了看laya 官方的例子,感觉看的一脸懵逼,早了半天的api 也没找到在哪有寻路的,最后一看代 […]...

展开目录

目录导航