PHP Traits代码复用方法浅析

       在看Yii的文档,Yii2用到了一个叫Traits的东西,查询文档可以知道自PHP5.4起,PHP实现了一个代码复用的方法,就是traits。官方的解释一大堆,翻译过来的晦涩难懂,我理解的意思就是——PHP是单继承语言,为了在不同结构的类里面复用一些方法,且不必像多继承类那样复杂,就使用了Traits来解决这类问题。简而言之,traits就是实现代码复用的方法。

1.使用简介

使用起来很简单,这个方法的官方名字是Traits,使用的时候是trait:

trait zz{
	function showMe(){
		echo "show me something in trails";
	}
}
class ZzTest{
	use zz;
}

$test = new ZzTest();
$test->showMe();
这里最终会打印出: show me something in trails

从基类继承的子类里使用traits的,会有一个覆盖的问题,我们看下面的代码。

trait zz{
	function showMe(){
		parent::showMe();
		echo "show me something in trails";
	}
}
class Father{
	function showMe(){
		echo "show me in Father<br/>";
	}
}
class ZzTest extends Father{
	use zz;
}
$test = new ZzTest();
$test->showMe();

最终会打印出:

show me in Father
show me something in trails

trait中的方法覆盖了父类的方法,所以执行的是trait中的showMe(),这里可以理解成子类中得到了trait作为自己的方法,覆盖了父类的方法。然后再看下面的代码:

trait zz{
	function showMe(){
		parent::showMe();
		echo "show me something in trails";
	}
}
class Father{
	function showMe(){
		echo "show me in Father<br/>";
	}
}
class ZzTest extends Father{
	use zz;
	public function showMe(){
		echo "show me MySelf";
	}
}
$test = new ZzTest();
$test->showMe();
结果会打印出: show me MySelf

子类中会覆盖Trait中的方法,优先级关系为子类 > trait> 基类。



2.多个trait

use声明时,列出多个trait,可以都插入到一个类中。

trait zz{
	function sayMe(){
		echo "Say me.";
	}
}
trait nn{
	function sayYou(){
		echo "Say you,";
	}
}
class ZzTest{
	use zz,nn;
	public function sayIt(){
		echo "Say it for always.";
	}
}
$test = new ZzTest();
$test->sayYou();
$test->sayMe();
$test->sayIt();
结果打印出: Say you,Say me.Say it for always.

如果trait中有重名的方法,会造成冲突:

trait zz{
	function sayMe(){
		echo "Say me.";
	}
	function sayYou(){
		echo "sAY YOU,";
	}
}
trait nn{
	function sayYou(){
		echo "Say you,";
	}
	function sayMe(){
		echo "sAY ME";
	}
}
class ZzTest{
	use zz,nn;
	public function sayIt(){
		echo "Say it for always.";
	}
}
 最终会报错: Fatal error : Trait method sayYou has not been applied, because there are collisions with other trait methods on ZzTest

   解决这个问题可以将同名的方法指定给另一个trait。

trait zz{
	function sayMe(){
		echo "Say me.";
	}
	function sayYou(){
		echo "sAY YOU,";
	}
}
trait nn{
	function sayYou(){
		echo "Say you,";
	}
	function sayMe(){
		echo "sAY ME.";
	}
}
class ZzTest{
	use zz,nn{
		nn::sayYou insteadof zz;
		zz::sayMe insteadof nn; 
	}
	public function sayIt(){
		echo "Say it for always.";
	}
}
$test = new ZzTest();
$test->sayYou();
$test->sayMe();
$test->sayIt();
指定使用trait nn中的sayYou(),和zz中的sayMe();最终打印出来也是: Say you,Say me.Say it for always.这里是指定使用哪一个,如果也想用另一个trait中的同名方法,就可以用as操作符将重名方法起一个别名,在之后的调用中使用别名。

use zz,nn{
		nn::sayYou insteadof zz;
		zz::sayMe insteadof nn; 
		zz::sayYou as sayYounn;
		nn::sayMe as asMenn;
	}
    起了别名之后在之后就可以调用他们

$test->sayYouzz();
$test->sayMenn();
//打印结果:sAY YOU,sAY ME.



3.方法的访问控制

trait默认的访问控制是public,也可以修改。这里需要知道一点,trait里的代码可以看作是孤立的代码段,然后拿这些放到类里面去用。类里面是如何定义的,这里就可以怎么写。

trait zz{
	public function sayYou(){
		$this->sayMe();
	}
	protected function sayMe(){
		echo "Say me.";
	}
}

class ZzTest{
	use zz;
	public function sayIt(){
		echo "Say it for always.";
	}
}
$test = new ZzTest();
$test->sayYou();
像这样是可行的,打印出:Say me.


用as就可以修改访问控制:

trait zz{
	protected function sayMe(){
		echo "Say me.";
	}
}
class ZzTest{
	use zz{
		sayMe as public;
	}
	public function sayIt(){
		echo "Say it for always.";
	}
}
$test = new ZzTest();
$test->sayMe();


4.trait组成trait

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

trait zz{
	function sayMe(){
		echo "Say me.";
	}
}
trait nn{
	function sayYou(){
		echo "Say you,";
	}
}
trait wj{
	use zz,nn;
}
class ZzTest{
	use wj;
}
$test = new ZzTest();
$test->sayYou();
$test->sayMe();
最后也是一样打印出:Say you,Say me.


5.trait的抽象成员

为了对使用trait的类施加强制要求,trait 支持抽象方法的使用。

trait zz{
	function sayYou(){
		echo "Say you,".$this->sayMe();
	}
	abstract public function sayMe();
}

class ZzTest{
	private $song = "Say me.";
	use zz;
	public function sayMe(){
		return $this->song;
	}
}
$test = new ZzTest();
$test->sayYou();
//结果依然是打印出:Say you,Say me.

6.其他特性

Traits 可以被静态成员静态方法定义,也可以定义属性。

trait zz{
	public $name = 'Say it for always.<br/>';
	function sayYou(){
        static $song = 'Say you,';
        echo $song.'Say me.';
    }
    public static function sing(){
    	echo 'That\'s the way it should be.';
    }

}

class ZzTest{
	use zz;
}
$test = new ZzTest();
$test->sayYou();
echo $test->name;
$test->sing();

最后打印结果送给你:

Say you,Say me.Say it for always.
That's the way it should be.








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值