开发者学堂课程【PHP 进阶教程-由浅入深掌握面向对象开发-第二阶段: Trait 同名】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/712/detail/12702
Trait 同名
主要内容
一、概念
二、步骤
三、示例
四、小结
一、概念
trait 同名是指一个类中可能引入多个 trait,而不同 trait 中可能出现同名。
1.trait 同名分为两类:
(1)属性同名:不允许出现同名属性,不管是多个 trait 还是类内部出现同名属性(trait 之间还是 trait 与类之间的同名属性)除非同名同值(就是一个属性,就不存在多个属性的情况。)
(2)方法同名:有两种对应的解决方案。
①不允许同名出现,但是已经出现可以使用替代方法,确定要用哪一个然后把一个作为主要的然后去替换另一个,那就意味在类里面使用时都只会用到其中一个。
语法:
Use trait 名1、trait 名2...{
trait 名1::方法名 insteadof(替换) trait 名2;
}
发现在使用整个 trait 类里面,只能用 trait1 的对应名,而 trait2 永远用不到,因为已经 trait1 替换掉了 trait2。
②不允许同名出现,如果出现了两个都要用,就使用别名,让两个都可以使用(使用别名前需要知道谁先代替谁,对被代替的使用别名)上面的只确定用一个,而下面的两个都可以用。
语法类似:将 trait2 的文件名替代 trait1 的文件名,就说明 trait1 的没有用了。将trait1as 一个别名之后会出现:trait1 方法可用,但是名字不可用。(别名使用)
以上是同名的处理;属性不能同名,除非同名同值;方法可以同名但是解决方案分为两类,一个是只用一个,一个是两个都要用(用别名)。
二、具体步骤:
1、定义多个 trait,里面存着同名方法。
2、在某个类中引入多个 trait(引入之后立马会报错,因为产生冲突了)
3、同名冲突后
(1)明确要用哪一个,insteadof 替换
(2)需要两个都用,使用别名临时修改同名中的一个。(不会改变原来 trait 中的名字,只是在类里面换了名字)
三、示例
1、trait 属性必须同名同值,否则报错
T1 里面有一个 public name的true,T2 里面也有 public name 叫 true。但是T1里面age=0,T2 里面 age=1,这就代表同名不同值。而 name 是同名同值的。
在一个类里面出现了同名问题,会出现的情况:
将上图的代码复制:
09trait-same
trait 同名成员问题
理论上没有这个的时候,是不会报错的。因为此时这两个同名是没有关系的,只要外面不同名就可以了。因为没有放在一起,所以不存在同名的问题。但是如果两个放在一起,就会出现问题。相当于将四行代码放在类里面,第一覆盖第二个 name都无所谓。但是第二个覆盖第一个是不可以的。
当再次测试的时候,就会出现 T2 define the sameproperty(age)只说了 age,但是在这里面不允许存在不同,因为系统不知道怎么区分。此时就需要用到别名来解。属性没有别名也没有替换的概念,所以就只能让它不存在。不允许同名出现,要换一个出现。例如可以将 age 改为 old,这样才能解决对应的问题。
以上是属性的问题,接下来为方法。方法如果又时也会出现冲突。将方法放进去,第一个方法是 eat。第二个方法也叫 eat,但是里面实现的业务是不一样的。此时的 Hume 不是对应上面的两个方法去的,或者是对其中一个方法的。但是另外的东西在上面还存在,用到了一个东西,这个只是其中的一部分,而这一部分恰恰影响了代码的整体性,因为显示已经存在了同样的问题。
所以系统解决不了同名的问题,需要使用别名。
(1)#trait 同名元素:替换使用其中一个
用到 insteadof 语法,需要用到 T2 的,因此直接 T2::eat insteadof T1 即可。
Use t2 t1{}
t2::eat insteadof t1
刷新之后发现没问题了。没问题之后自然就可以用了。
$H=new human
$h->eat
刷新后明显发现 t2 的 eat 被触发。因为上面明确指出用了 t2::eat insteadof t1
(2)两个都要使用。使用别名处理;保证两个方法都能使用。但是先要确定用哪一个,然后再去替换另外一个。
用 t1::eat insteadof t2;
T2::eat as show; 改为 show2 或者 show 都可以。
将第一种方案注释掉。
#trait 同名元素:别名保留两个方法。
USEt1,t2{ // 这两个顺序没有关系
t1::eat insteadof t2 #具体使用 t1::eat 方法//这是保留的。
t2::eat as show #t2::eat 临时改名为 show。
有了以上操作之后,看看代码能否运行。刷新之后发现没有问题,此时访问的是 t1的 eat,但是想要使用另一个方法就只能使用 show 了,已经有别名替代了。发现两个方法都可以用了。
以上就是解决方案,此部分解决完之后如果将 t1 引入的只有一个 trait 但是要给它改别名,也是可以的。
(4)补充:
Class animal{}
Use t1
$a=new animal
$a->eat()
运行之后发现没有问题,但是此时运行的时候是强行别名的。
T1::eat as show
在没有报错的情况下,调用 eat,说明将 eat 改为 show 这个 eat 的方法还在。先调用 show 发现也是可以访问的。
本质逻辑:
trait 别名不会改变原来方法的存在,而是相当于复制了一个别名的方法(相当于定义了一个 show 的方法,但是用的是 eat 方法的内容)前面的代码本质也是如此。只不过规定了 t1 的 eat 比谁都大,外部调用的时候只能使用它,因此会发现 t2 的 eat 并没有消失。只是取了一个别名,多了一个方法而已。以上就是别名使用。
四、小结
1、trait 同名概率出现比较小,但是要警惕出现同名(在写代码的时候不愿意让这个东西出现同名,因为同名之后会影响自己之后的操作。因此代码是自己写的,不会出现同名的问题。上面出现了 eat 下面就换成 person 或者 person animal-eat。下面的方法明显与上面的方法不同名)
2、解决 trait 同名(不能修改上面的代码,因此需要来处理它)
属性同名,除非同值,不然只能改源码。
方法本身可以进行同名处理
只要用到一个替换的方式明确使用其中一个。如果说需要用到两个,让另外一个与当前的不冲突,只是使用别名也需要提前明确使用哪一个。这是 trait 特性。
3、如果出现了同名,需要考虑用什么样的方式来解决。根据业务来支撑。
上述代码出现了很多同名的东西,本身里面:class animal 把 t1::eat as show这时允许自己有一个 eat function。Echo”animal“
自己有自己的 eat 方法,但是与其他又同名了。其他的取别名不影响。第一个调用的 eat 是自己的。
所以别名使用之后优先级就会降低,当然这里涉及到重写的问题,也就是可能会存在同名的情况出现的概率
以上是 trait 出现同名的问题。