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 闭包

    浅谈PHP闭包 Closure和Callable区别Closure 必须是匿名函数, callable 同时还可以为可调用函数名区别示例function func1(callable $callable){return $ca...

  2. 设计模式之代理模式–PHP

    代理模式是常用的设计模式之一,代理模式为对象的间接访问提供了一套方案,可以对对象访问进行控制,也能监控对象访问 […]...

  3. Yii2.0源码阅读-视图(View)渲染过程

    Yii2.0源码阅读-视图(View)渲染过程 之前的文章我们根据源码的分析,弄清了Yii如何处理一次请求,以 […]...

  4. Swoole 是 PHP 中的 Node.js?

    一想到那些可以使用 Node 的同事,一些 PHP 开发者的脸都嫉妒绿了。异步 Node 系统可以在不同协议间 […]...

  5. PHP 的一些底层知识

    本篇内容比较干涩,请自备矿泉水 文章分6个主题进行讲解 PHP运行机制和原理 PHP底层变量数据结构 PHP传 […]...

  6. 影响 POST 请求文件上传失败的几个环节的配置(php + nginx)

    写在前面 最近写一个 php 接口,接受上传的文件,发现文件只要超过 5m 以上就会无响应失败,最后发现是 s […]...

  7. PHP 安装

    2)下载安装PHP下载地址:https://windows.php.net/download 注意:下载完成,解压后就意味着安装成功。3)验证安装成功win+R 调出命令行终端,进入到PHP安装目录,输入php -v 得到以下信息...

  8. 【每日函数】每日函数(2021.08.06)

    每日函数(2021.08.06) 一梦千年系列 array_diff_assoc1 带索引检查数组的差集 说明 […]...

随机推荐

  1. word图表的自动编号

    word图表的自动编号分为几种类型,本文包含的内容主要分为三个部分: 1.图表的普通自动编号; 2.图表的自动 […]...

  2. word中中文保持正体,英文用斜体的方法.

    有时候,大段的文字中夹杂着英文字母,英文需要斜体,如果一个接一个选中再斜体,费时费力,那么怎样快速实现文斜体中 […]...

  3. 7-31 堆栈操作合法性 (20 分) PTA

    7-31 堆栈操作合法性 (20 分)   假设以S和X分别表示入栈和出栈操作。如果根据一个仅由S和X构成的序 […]...

  4. CentOS 7定时执行python脚本

    在CentOS下,可以使用crontab进行定时任务的处理。 一、crontab的安装 默认情况下,CentO […]...

  5. Dart语言特性必备了解!

    学习Dart语言,必须将以下的概念熟记于心: 在dart语言中,一切皆为对象。所有的对象都是一个类的实例。甚至 […]...

  6. 大量CLOSE_WAIT的本质

    http://ahuaxuan.iteye.com/blog/657511 /*  * @author: ah […]...

  7. 学习git这一篇就够了!!!

    从0开始学习git,这一篇就够了。 ##git命令操作 本地库操作 初始化本地仓库 初始化命令 git ini […]...

  8. this的四种用法

    在函数执行时,this 总是指向调用该函数的对象。 要判断 this 的指向,其实就是判断 this 所在的函 […]...

展开目录

目录导航