配色: 字号:
php trait 多重继承的实现案例
2016-08-16 | 阅:  转:  |  分享 
  
phptrait多重继承的实现案例

自PHP5.4.0起,PHP实现了代码复用的一个方法,称为traits。

Traits是一种为类似PHP的单继承语言而准备的代码复用机制。Trait为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用方法集。Traits和类组合的语义是定义了一种方式来减少复杂性,避免传统多继承和混入类(Mixin)相关的典型问题。

Trait和一个类相似,但仅仅旨在用细粒度和一致的方式来组合功能。Trait不能通过它自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用类的成员不需要继承。

在我理解说白了就是在继承类链中隔离了子类继承父类的某些特性(就是子类“要用父类的特性的时候”,如果trait有,就优先调用trait的方法、属性等)。

var.PHP_EOL;???}????functiona()???{???????echo"a".PHP_EOL;???}}?interfaceMyInterface{???function__construct();???functionb();}?abstractclassMyAbstract{???protected$var2="MyAbstract_var";????useMyTrait;????functionb()???{???????echo"b".PHP_EOL;???}}?classMyClassextendsMyAbstractimplementsMyInterface{???protected$var3="MyClass_var";????//也可以在这里引用,不区分继承关系???//useMyTrait;???functionc()???{???????echo"c".PHP_EOL;???}}?$class=newMyClass();$class->a();$class->b();$class->c();

输出结果

MyTrait_varabc

优先级

从基类继承的成员被trait插入的成员所覆盖,来自当前类的成员覆盖trait的方法。

classBase{???publicfunctionsayHello(){???????echo''Hello'';???}}

traitSayWorld{???publicfunctionsayHello(){???????parent::sayHello();???????echo''World!'';???}???publicfunctionsayHellos(){???????echo''HelloWorld!'';???}}

classMyHelloWorldextendsBase{???useSayWorld;

???publicfunctionsayHellos(){???????echo''HelloUniverse!'';???}}

$o=newMyHelloWwww.shanxiwang.netorld();$o->sayHello();?#HelloWorld!$o->sayHellos();?#HelloUniverse!3、多个trait

通过逗号分隔,在use声明列出多个trait,可以都插入到一个类中。

traitHello{???publicfunctionsayHello(){???????echo''Hello'';???}}

traitWorld{???publicfunctionsayWorld(){???????echo''World'';???}}

classMyHelloWorld{???useHello,World;}

$o=newMyHelloWorld();$o->sayHello();#Hello$o->sayWorld();#World4、多Traits冲突的解决

如果两个trait都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。

为了解决多个trait在同一个类中的命名冲突,需要使用insteadof操作符来明确指定使用冲突方法中的哪一个。

以上方式仅允许排除掉其它方法,as操作符可以将其中一个冲突的方法以另一个名称来引入。

traitA{???publicfunctionsmallTalk(){???????echo''a'';???}???publicfunctionbigTalk(){???????echo''A'';???}}

traitB{???publicfunctionsmallTalk(){???????echo''b'';???}???publicfunctionbigTalk(){???????echo''B'';???}}

classTalker{???useA,B{???????B::smallTalkinsteadofA;???????A::bigTalkinsteadofB;???}}

classTalkers{???useA,B{???????B::smallTalkinsteadofA;???????A::bigTalkinsteadofB;???????B::bigTalkasbTalk;???}}

$o=newTalker();$o->smallTalk();#b$o->bigTalk();#A

$os=newTalkers();$os->smallTalk();#b$os->bigTalk();#A$os->bTalk();#B5、修改方法的访问控制

还可以使用as语法来改变Traits中函数的访问权限属性。

traitHelloRuesin{???publicfunctionsayHello(){???????echo''HelloRuesin'';???}}

classHello{???useHelloRuesin{???????sayHelloasprotected;##修改sayHello的访问控制???}}

classRuesin{???useHelloRuesin{???????sayHelloasprivatesayHellos;##给方法一个改变了访问控制的别名而原版sayHello的访问控制则没有发生变化???}}

$o?=newHello();$os=newRuesin();#$o->sayHello();#无法访问$os->sayHello();#HelloRuesin#$os->sayHellos();#无法访问6、用Traits组成新Traits

正如类能够使用trait一样,其它trait也能够使用trait。在trait定义时通过使用一个或多个trait,它能够组合其它trait中的部分或全部成员。

traitHello{???publicfunctionsayHello(){???????echo''Hello'';???}}

traitRuesin{???publicfunctionsayRuesin(){???????echo''Ruesin'';???}}

traitHelloRuesin{???useHello,Ruesin;}

classSayHelloRuesin{???useHelloRuesin;}

$o=newSayHelloRuesin();$o->sayHello();?#Hello$o->sayRuesin();#Ruesin7、Trait的抽象成员

为了对使用的类施加强制要求,trait支持抽象方法的使用。表示通过抽象方法来进行强制要求

traitHello{???publicfunctionsayHelloRuesin(){???????echo''Hello''.$this->getName();???}???abstractpublicfunctiongetName();}

classHelloRuesin{???private$name;???useHello;???publicfunction__construct($name){???????$this->name=$name;???}???publicfunctiongetName(){???????return$this->name;???}}

(newHelloRuesin(''Ruesin''))->sayHelloRuesin();#HelloRuesin8、trait的静态成员

静态变量可以被trait的方法引用,但不能被trait定义。Traits能够为使用的类定义静态方法。

traitCounter{???publicfunctioninc(){???????static$c=0;???????$c=$c+1;???????echo"$c\n";???}

???publicstaticfunctionHelloRuesin(){???????#return''Doingsomething'';???????echo''HelloRuesin'';???}}

classC{???useCounter;}

$o=newC();?$o->inc();#1$o->inc();#2C::HelloRuesin();#HelloRuesin''9、Trait定义属性

文章来自ruesin.com

如果trait定义了一个属性,那类将不能定义同样名称的属性,否则会产生一个错误。如果该属性在类中的定义与在trait中的定义兼容(同样的可见性和初始值)则错误的级别是E_STRICT,否则是一个致命错误。

Ruesin''sBlogtraitPropertiesTrait{???public$x=1;}

classPropertiesExample{???usePropertiesTrait;???#public$same=true;#StrictStandards???#public$different=true;#致命错误}

$example=newPropertiesExample;$example->x;#1

总结:

从本质上说,trait和include文件的概念差不多

trait可以更加方便的实现代码复用,因为我们用继承关系实现的无法在父类中访问子类的private属性与方法,而trait就和把代码直接写在对象里效果一样。

使用trait时候应该坚决避免命名冲突,尤其是同时使用多个trait时。如果产生了命名冲突,如果两者的可见性、初始值、static与否完全相同,则trait中的会覆盖掉对象中的,并抛出E_STRICT错误,否则会抛出E_COMPILE_ERROR错误,终止编译。



献花(0)
+1
(本文系网络学习天...首藏)