简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

PHP的类是单一继承模式,也就是每个类只能继承一个父类(基类)。

但有时需要引入更多通用(共用)的方法,同时这些方法又不适合集成到基类。

那么这时,就需要使用其他方法来引入这些方法。其中trait,就是方法之一。

trait是PHP5.4之后出现的一种代码复用方法,形式和Class非常相似,同时可以随意组合任意引入。

trait一般在当前类和其同父类(基类)的其他类都需要使用相同方法时,而其父类(基类)又要尽量避免出现这些方法时使用。

甚至有时可能其他关联不是特别大的类(分别继承不同的父类)也可能会使用共同的方法,也可以使用trait的方法。

 

尽量通俗一点的说一下trait:

trait像类,但不是类,不可以直接使用new关键字创建对象;简单理解是用类的形式,封装一大堆通用(共用)的方法,供其他类引用。

trait和use搭配使用。定义好trait后,“use trait定义的名字;”,就可以直接使用里边定义的一切了,是不是很简单?很方便?

现在知道了trait,接下来就通过代码实例,演示一下trait的具体使用和一些小情况。

 

一、trait的使用

代码:

// trait
trait traitTest {
    public function test() {
        echo "trait test...\n";
    }
}
// 父类
class ParentClass {
    public function parent() {
        echo "parent...\n";
    }
}
// 子类
class SubClass extends ParentClass {
    use traitTest;
    public function sub() {
        echo "sub...\n";
    }
}

$obj = new SubClass;
$obj->sub();// 调用子类方法
$obj->parent();// 调用父类的方法
$obj->test();// 调用trait里的方法

代码和结果截图:

 

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

上边的这个例子,子类直接extentds父类,然后又在类内use了trait。这样当前类(子类)就拥有了这三个的全部方法。

子类的sub方法,父类的parent方法,trait的test方法,在子类内都可以直接调用使用。

最基础的使用就这些,看起来是不是也不算难?甚至感觉挺简单的?

那么我们进一步思考一下,类的“继承”难免会出现同名方法,那么这三个里边如果有同名方法,最终会保留哪个?谁的方法会被覆盖呢?

 

二、当父类、子类和trait的方法重名

代码:

// trait
trait traitTest {
    public function test() {
        echo "trait test...\n";
    }
    public function lookClassName() {
        echo "trait here\n";
        echo __CLASS__ . "\n";
    }
}
// 父类
class ParentClass {
    public function parent() {
        echo "parent...\n";
    }
    public function lookClassName() {
        echo __CLASS__ . "\n";
    }
}
// 子类
class SubClass extends ParentClass {
    use traitTest;

    public function sub() {
        echo "sub...\n";
    }
    public function lookClassName() {
        echo __CLASS__ . "\n";
    }
}

$obj = new SubClass;
$obj->sub();// 调用子类方法
$obj->parent();// 调用父类的方法
$obj->test();// 调用trait里的方法
$obj->lookClassName();// 调用同名方法

代码和结果截图:

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

上边这段例子的结果很明显的发现,最终当前类(子类)的方法被调用了,也就是三个里边都有同名方法时,当前类的方法优先。

接下来,注释(删除)当前类的lookClassName()方法。

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

看上边截图,很明显了,当子类(当前类)没有同名方法,只有父类(基类)和trait中的方法同名时,trait中的方法优先。

结论:当前类(子类)、trait和父类(基类)中有同名方法时“子类高于trait高于父类”。子类的方法会覆盖trait中的方法,而trait的方法会覆盖父类的方法。

 

前边有提到,trait可以随意组合,随意引用,那么是不是可以同时引入多个trait呢?是。在一个类内,可以同时use多个trait。

 

三、类内同时引入多个trait

// trait
trait traitTest {
    public function test() {
        echo "trait test...\n";
    }
    public function lookClassName() {
        echo "trait here\n";
        echo __CLASS__ . "\n";
    }
}

trait traitTest2 {
    public function test2() {
        echo "trait2 test...\n";
    }
    public function lookClassName() {
        echo "trait2 here\n";
        echo __CLASS__ . "\n";
    }
}

trait traitTest3 {
    public function test3() {
        echo "trait3 test...\n";
    }
    public function lookClassName() {
        echo "trait3 here\n";
        echo __CLASS__ . "\n";
    }
}
// 父类
class ParentClass {
    public function parent() {
        echo "parent...\n";
    }
    public function lookClassName() {
        echo __CLASS__ . "\n";
    }
}
// 子类
class SubClass extends ParentClass {
    use traitTest;
    use traitTest2, traitTest3;
    
    public function sub() {
        echo "sub...\n";
    }
    public function lookClassName() {
        echo __CLASS__ . "\n";
    }
}

$obj = new SubClass;
$obj->sub();// 调用子类方法
$obj->parent();// 调用父类的方法
$obj->test();// 调用trait里的方法
$obj->test2();// 调用trait2里的方法
$obj->test3();// 调用trait3里的方法
$obj->lookClassName();// 调用同名方法

代码和结果截图:

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

当需要同时引入多个trait时,只要use trait1, trait2, trait3,在use后边跟多个trait名字即可,多个trait之间用逗号分隔。

当然,也可以分开写,每次use一个trait进来。

此时又有新的问题产生了,如果引入的多个trait都有同名的方法,那么又会是谁优先?谁又被覆盖呢?

 

四、引入多个trait有同名方法

代码:

// trait
trait traitTest {
    public function test() {
        echo "trait test...\n";
    }
    public function lookClassName() {
        echo "trait here\n";
        echo __CLASS__ . "\n";
    }
}

trait traitTest2 {
    public function test2() {
        echo "trait2 test...\n";
    }
    public function lookClassName() {
        echo "trait2 here\n";
        echo __CLASS__ . "\n";
    }
}

trait traitTest3 {
    public function test3() {
        echo "trait3 test...\n";
    }
    public function lookClassName() {
        echo "trait3 here\n";
        echo __CLASS__ . "\n";
    }
}
// 父类
class ParentClass {
    public function parent() {
        echo "parent...\n";
    }
    public function lookClassName() {
        echo __CLASS__ . "\n";
    }
}
// 子类
class SubClass extends ParentClass {
    use traitTest, traitTest2, traitTest3 {
        traitTest2::lookClassName insteadof traitTest;// traitTest2代替了traitTest
        traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2
    }
    
    public function sub() {
        echo "sub...\n";
    }
    // public function lookClassName() {
    //     echo __CLASS__ . "\n";
    // }
}

$obj = new SubClass;
$obj->sub();// 调用子类方法
$obj->parent();// 调用父类的方法
$obj->test();// 调用trait里的方法
$obj->test2();// 调用trait2里的方法
$obj->test3();// 调用trait3里的方法
$obj->lookClassName();// 调用同名方法

代码和结果截图:

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

说明(上边的源码和结果是解冲突之后的): 

当子类没有(注释或者删除)lookClassName()方法时,调用lookClassName方法,则会调用trait中的方法,因为三个trait中都有同名方法,此时就会发生致命错误(冲突)。

报下边(看截图)的语法错误

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

此时,就需要解冲突。

解冲突,就需要使用到insteadof关键字,含义是“代替”,就是用哪个代替哪个。

    use traitTest, traitTest2, traitTest3 {
        traitTest2::lookClassName insteadof traitTest;// traitTest2代替了traitTest
        traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2
    }

解引入多个trait多个重名方法冲突时,需要在引入时使用insteadof关键字,逐一说明哪个trait的方法代替了哪个trait的(看上边引入代码的注释)。

根据上边引入的代码,是traitTest2的lookClassName代替了traitTest的,然后traitTest3的代替了traitTest2的。

因此,最终输出结果时,调用lookClassName(),输出的就是traitTest3的内容(输出结果看上边最近的“代码和结果截图”)。

当然,也可以换个写法:

    use traitTest, traitTest2, traitTest3 {
        traitTest2::lookClassName insteadof traitTest3;// traitTest2代替了traitTest3
        traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2
    }

这个写法呢,是traitTest2和traitTest3互相代替了,那么此时反而没有traitTest什么事了。这个时候,再调用lookClassName()方法,输出的就是traitTest的lookClassName()方法的内容。

代码和结果截图:

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

如图,当traitTest2和traitTest3互相代替后,直接输出了traitTest的内容。

 

到这基本就该结束了,但,有个特殊情况需要考虑一下。

我们之所以会引入多个trait,说明这几个trait里都有想使用的方法,那么非常巧合,其中同名方法正好又都想使用,被代替的方法还能使用么?

 

五、当引入多个trait,同名方法解冲突后,同时使用所有冲突的同名方法

解决:我们需要使用到另一个关键字“as”,此关键字的功能,简单理解就是给方法取一个别名。

代码:

// trait
trait traitTest {
    public function test() {
        echo "trait test...\n";
    }
    public function lookClassName() {
        echo "trait here\n";
        echo __CLASS__ . "\n";
    }
}

trait traitTest2 {
    public function test2() {
        echo "trait2 test...\n";
    }
    public function lookClassName() {
        echo "trait2 here\n";
        echo __CLASS__ . "\n";
    }
}

trait traitTest3 {
    public function test3() {
        echo "trait3 test...\n";
    }
    public function lookClassName() {
        echo "trait3 here\n";
        echo __CLASS__ . "\n";
    }
}
// 父类
class ParentClass {
    public function parent() {
        echo "parent...\n";
    }
    public function lookClassName() {
        echo __CLASS__ . "\n";
    }
}
// 子类
class SubClass extends ParentClass {
    use traitTest, traitTest2, traitTest3 {
        traitTest2::lookClassName insteadof traitTest3;// traitTest2代替了traitTest3
        traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2
        traitTest2::lookClassName as lookClassName2;// traitTest2的lookClassName改别名lookClassName2
        traitTest3::lookClassName as lookClassName3;// traitTest3的lookClassName改别名lookClassName3
    }
    
    public function sub() {
        echo "sub...\n";
    }
    // public function lookClassName() {
    //     echo __CLASS__ . "\n";
    // }
}

$obj = new SubClass;
$obj->sub();// 调用子类方法
$obj->parent();// 调用父类的方法
$obj->test();// 调用trait里的方法
$obj->test2();// 调用trait2里的方法
$obj->test3();// 调用trait3里的方法
$obj->lookClassName();// 调用同名方法
$obj->lookClassName2();// 调用traitTest2更名后的同名方法
$obj->lookClassName3();// 调用traitTest3更名后的同名方法

代码和结果截图:

简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理

根据上图,就可以看出,当trait2和trait3互相代替,然后同名方法另起别名后,三个trait的同名方法,不再冲突,并且可以分别调用各自原本同名的方法。

到此要说的东西基本都说完了。算是对PHP的trait的一个小小的总结,希望可以帮到需要的朋友。

若有不对之处,请赐教。

 

原文链接:https://www.cnblogs.com/leafinwind/p/17354416.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:简述PHP中trait的使用和同时引入多个trait时同名方法冲突的处理 - Python技术站

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

相关文章

  • matlab2014a怎么激活?matlab2014a安装破解激活图文详细教程

    如果你想要激活Matlab2014a,并且想要了解更具体的安装破解激活过程,可以按照以下步骤来操作: 步骤1:下载Matlab 首先,在Math Works官网上找到Matlab2014a的下载链接,下载完整版的Matlab2014a安装包。 步骤2:安装Matlab 下载完成后,打开Matlab的安装包文件,并根据提示进行安装。安装过程中,需要注意选择合适…

    PHP 2023年5月27日
    00
  • php简单分页类实现方法

    让我来为您详细讲解“PHP简单分页类实现方法”的完整攻略。 1. 确定分页需求 在开始实现分页类之前,需要了解分页的具体需求,例如每页显示数量、总数据量、当前页码等,这些信息将作为分页类的初始化参数。在本次示例中,我们假设需求如下: 每页显示10条数据; 总共有100条数据; 当前页码为2。 2. 实现分页类 2.1 确定类的属性和方法 根据需求,我们需要实…

    PHP 2023年5月27日
    00
  • php strstr查找字符串中是否包含某些字符的查找函数

    strstr() 函数用于查找字符串中是否包含某些字符,并返回第一个匹配的位置。该函数包含两个参数:要查找的字符(needle)和要被查找的字符串(haystack)。如果找到了匹配的字符,则该函数返回第一次出现该字符的位置。否则,该函数返回 false。 以下是使用 strstr() 函数的一些常见用途: 检查字符串中是否包含某个特定的单词或字符 示例代码…

    PHP 2023年5月26日
    00
  • PHP7数组的底层实现示例

    下面是 PHP7 数组的底层实现示例的详细攻略。 什么是 PHP7 数组? PHP7 数组指的是 PHP 语言中的数组类型,它是一种可以存储多个值的数据类型。PHP 数组的特点是可以动态地添加、删除和修改元素,而且支持多种不同类型的元素。在 PHP7 中,数组的底层实现有了很大改进,提高了数组的性能和效率。 PHP7 数组的底层实现 PHP7 数组的底层实现…

    PHP 2023年5月27日
    00
  • php实现微信公众号企业转账功能

    下面是 “php实现微信公众号企业转账功能”的完整攻略: 1. 申请开通微信支付 在使用微信支付进行企业转账前,需要先在微信商户平台中开通微信支付功能,并获取到商户号(mchid)、api密钥(api_key)和证书文件等信息。 2. 下载微信支付SDK文件 官方提供了微信支付的SDK文件,下载后解压到本地目录。 3. 接入微信支付SDK文件 将下载的微信支…

    PHP 2023年5月23日
    00
  • PHP代码覆盖率统计详解

    PHP代码覆盖率统计详解攻略 什么是代码覆盖率 在软件测试过程中,代码覆盖率是一个重要的概念。代码覆盖率是指在测试中执行了多少代码行或语句的百分比。对于代码质量的评估来说,代码覆盖率是一个重要的指标。 为什么需要代码覆盖率 对于一个项目来说,代码覆盖率可以帮助我们评估测试的质量,确定测试的覆盖面积,还可以帮助我们发现代码中的潜在问题,减少后期维护的成本。 P…

    PHP 2023年5月23日
    00
  • php实现的AES加密类定义与用法示例

    下面我将详细讲解“PHP实现的AES加密类定义与用法示例”的攻略。 简介 AES是一种对称密钥加密算法,目前广泛使用于各类系统中。在PHP中实现AES加密需要用到openssl扩展。本文将介绍如何在PHP中实现AES加密,并提供一个封装好的AES加密类。 安装openssl扩展 PHP实现AES加密需要安装openssl扩展,如果已经安装则可忽略此步骤。可以…

    PHP 2023年5月26日
    00
  • 4种PHP异步执行的常用方式

    异步执行的概念 在传统的 PHP 程序中,代码是同步执行的,也就是一行一行地执行,在执行完一行代码之后,才会去执行下一行代码。这种方式通常是顺序执行的,如果这条代码很耗时,程序就会停滞在这里,不能做其他的事情。 而异步执行则是指一种非阻塞的操作,也就是在执行某个操作的时候,不会阻塞后面的代码执行。例如,在后台执行一个任务的时候,我们可以异步执行该任务,使得程…

    PHP 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部