面向对象 - trait代码共享

  • 作者:KK

  • 发表日期:2017.9.22


快速示例

//定义一个叫 CommonMethod 的trait,就像定义类一样
trait CommonMethod{
	public $attr = 'abc';

	public static function haha(){
		return 'haha';
	}

	public function test1(){
		return $this->name;
	}

	public function test2(){
		return 222;
	}
}

class A{
	//引用上面的trait
	use CommonMethod;

	public $name = 'aaa';

	public function test3(){
		return 333;
	}
}

class B{
	//也引用上面的trait
	use CommonMethod;

	public $name = 'bbb';

	public function test4(){
		return 333;
	}
}


$a = new A();
$b = new B();
print_r([
	A::haha(),	//haha	这是trait里的方法
	$a->test1(),	//aaa	也是trait的方法,可是返回了A类的name属性
	$a->test2(),	//222	trait的方法
	$a->attr,	//abc

	B::haha(),	//haha	这也是trait里的方法
	$b->test1(),	//bbb	道理同上
	$b->test2(),	//222
	$b->attr,	//abc
]);

上面例子中,A和B的类里面第一句就是use CommonMethod,而这个CommonMethod指的就是开头定义的trait CommonMethod

简单地说trait关键词就是定义了一块公共代码,这块代码要起一个标识符于是我设定为CommonMethod,其它类要引用这块代码,就在类里面直接use代码标识符就行了,等于复制粘贴代码进来一样,然而这样并不是继承一个类,它不增加类的继承链,而仅仅是把另一块代码贴到自己身上扩展功能而已

这看上去跟继承的效果一模一样,但有时候我们既要继承某个类,又要与其它类拥有共同的某些方法,用这招就比较合适了


可以include

你可以在一个单独的文件里定义trait,然后在别处include进来,就像include一个类一样而已


类里面可以use多个trait

比如定义t1、t2和t3三个trait,可以下面这样直接多次use

class A{
	use t1;
	use t2;
	use t3;

	public $xxx = 123;
}

可以有命名空间

namespace app\common;

trait MyMethods{
	//...
}

命名空间马上会在后面讲到,而引用的时候就是带上命名空间:use app\common\MyMethods


可以autoload

如果use了一个不存在的trait,会自动触发autoload

其实就跟自动加载一个类一样,如果use CommonMethod33,autoload会收到一个参数,值就是字符串“CommonMethod33

如果use app\common\Methods,则autoload收到的参数也是“app\common\Methods


trait不能定义常量

虽说它就像一块公共代码一样可以被别的类use引用,但下面这样定义常量是支持的

trait Test{
	const STATUS_ACTIVE = 1;
}