<?php
/**
* Created by PhpStorm.
* User: YANGHY
* Date: 2020/4/29
* Time: 10:21
*/
/**
* Class TestTrait
* Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。
* Trait 为了减少单继承语言的限制,在不同层次结构内独立的类中复用 method。
* Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。
* 优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。
*
*/
//例子1 单个trait的使用
/**trait TraitExample{
public function add($a,$b){
return $a + $b;
}
public function sub($a, $b){
return $a - $b;
}
}
class TestTrait
{
use TraitExample; // 使用trait
}
$obj = new TestTrait();
echo $obj->add(10,12)."\n";
echo $obj->sub(12,2);**/
//例子2 优先级
//trait TraitExample{
// public function add($a,$b){
// return $a + $b;
// }
// public function sub($a, $b){
// return $a - $b;
// }
//}
//class Count{
// public function add($a,$b){
// return $a + $b + 100;
// }
// public function sub($a, $b){
// return $a - $b + 100;
// }
//}
//class TestTrait extends Count
//{
// public function add($a,$b){
// return $a + $b + 200;
// }
// public function sub($a, $b){
// return $a - $b + 200;
// }
// use TraitExample; // 使用trait
//}
//$obj = new TestTrait();
//echo $obj ->add(10,10)."\n"; // 220
//echo $obj ->sub(10,10); // 200
// 例子3 多个trait通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。
/*trait Ex1{
public function say(){
echo "hello";
}
}
trait Ex2{
public function reply(){
echo "hi";
}
}
class Test{
use Ex1,Ex2; // 引用多个trait
}
$obj = new Test();
$obj ->say();
echo "\n";
$obj ->reply();*/
// 4.多个trait中同名函数冲突解决方法
// insteadof 明确使用哪一个
/*trait Ex1{
public function say(){
echo "Ex1 say hello";
}
public function replay(){
echo "Ex1 reply hi";
}
}
trait Ex2{
public function say(){
echo "Ex2 say hello";
}
public function replay(){
echo "Ex2 reply hi";
}
}
class Test{
use Ex1,Ex2{
Ex2::say insteadof Ex1; // 使用 insteadof明确使用哪个 例如使用Ex2的say
Ex1::replay insteadof Ex2; // 使用 Ex1的replay
} // 引用多个trait
}
$obj = new Test();
$obj ->say(); // Ex2 say hello
echo "\n";
$obj ->replay(); // Ex1 reply hi*/
// as 引入别名
/*trait Ex1{
public function say(){
echo "Ex1 say hello";
}
public function replay(){
echo "Ex1 reply hi";
}
}
trait Ex2{
public function say(){
echo "Ex2 say hello";
}
public function replay(){
echo "Ex2 reply hi";
}
}
class Test{
use Ex1,Ex2{
Ex1::say insteadof Ex2;
Ex1::replay insteadof Ex2;
Ex2::say as Esay;
Ex2::replay as Ereplay;
} // 引用多个trait
}
$obj = new Test();
$obj ->say(); // Ex1 say hello
echo "\n";
$obj ->replay(); // Ex1 reply hi
echo "\n";
$obj ->Esay(); // Ex2 say hello
echo "\n";
$obj ->Ereplay(); // Ex2 say hi*/
// 修改方法的访问控制权限
/*trait Control{
public function getC(){
echo "public";
}
}
class Test{
use Control{
// getC as private; // 修改方法权限
getC as private getByC;//原版 getC 的访问控制并没有发生变化,生成的新的getByC控制权限为private
}
public function getControl($className,$method){
$reflection = new ReflectionMethod($className,$method);
$result = Reflection::getModifierNames($reflection->getModifiers());
print_r($result);
}
}
//
$obj = new Test();
// Array
// (
// [0] => private
// )
$obj ->getControl('Test','getC');
$obj ->getControl('Test','getbyC');
*/
//trait组成trait
/*trait Hello{
public function hello(){
echo "hello";
}
}
trait World{
public function world(){
echo "world";
}
}
trait HelloWorld{
use Hello,World;
}
class MyHelloWorld{
use HelloWorld;
}
$obj = new MyHelloWorld();
$obj ->hello();
echo " ";
$obj ->world();*/
//trait的抽象成员 为了对使用的类强制要求,trait支持抽象方法的使用
/*trait Hello{
public function sayHello(){
echo "hello ".$this->getWorld();
}
abstract function getWorld();
}
class Test{
use Hello;
private $world;
function getWorld()
{
return $this->world;
}
function setWorld($value){
$this ->world = $value;
}
}
$obj = new Test();
$obj ->setWorld("world!");
$obj ->sayHello();*/
// trait 可以被静态成员和静态方法定义
/*trait StaticVf{
static $a = 'kral';
static public function say(){
echo "今天的天气可真好!";
}
}
class Test{
use StaticVf;
}
echo Test::$a;
Test::say();*/
// trait Trait 定义了一个属性后,类就不能定义同样名称的属性,否则会产生 fatal error。
// 有种情况例外:属性是兼容的(同样的访问可见度、初始默认值)。 在 PHP 7.0 之前,属性是兼容的,则会有 E_STRICT 的提醒。
/*trait StaticV{
public $a = true;
public $b = false;
}
class Test{
use StaticV;
public $a = "hello"; // Fatal error 测试版本php 7.3.1
public $b = false; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
}
$obj = new Test();*/
// 与继承不同;如果trait具有静态属性,则使用该trait的每个类都具有这些属性的独立实例。
// 继承
/*class StaticV{
static $a;
}
class TestStaticv extends StaticV{
}
class TestStaticv2 extends StaticV{
}
TestStaticv::$a = 'hello';
TestStaticv2::$a = 'world';
echo TestStaticv::$a.' '.TestStaticv2::$a; // World World*/
/*trait StaticV{
static $a;
}
class TestTrait{
use StaticV;
}
class TestTrait2{
use StaticV;
}
TestTrait::$a = 'hello';
TestTrait2::$a = 'world';
echo TestTrait::$a.' '.TestTrait2::$a; // hello world*/
// __CLASS__ 返回使用trait的类的名称,不是调用trait方法的类
/*trait MyTrait{
public function TestTrait(){
echo "CLASS: ".__CLASS__;
echo "TRAIT: ".__TRAIT__;
}
}
class BaseClass{
use MyTrait;
}
class TestBaseClass extends BaseClass{
}
$obj = new TestBaseClass();
$obj ->TestTrait();*/
// traits与继承的另一个区别是,traits中定义的方法可以访问它们使用的类的方法和属性,包括私有类。
/*trait MyTrait{
protected function setVar(){
return $this ->var;
}
}
class TraitUser{
use MyTrait;
private $var = 'var';
public function getVar()
{
return $this ->setVar($this->var);
}
}
$obj = new TraitUser();
echo $obj->getVar();*/
// 如前所述,trait中的静态属性和方法可以使用trait直接访问。由于trait是语言辅助的c/p,
//您应该注意,trait中的静态属性将被初始化为trait属性在类声明时的值。
/*trait Base{
protected static $a = 'Right';
public static function printed(){
echo static::$a.PHP_EOL;
}
public static function setType($value){
static::$a = $value;
}
}
class Test{
use Base;
}
Base::setType('Left');
class Test2{
use Base;
}
Base::setType('Center');
Base::printed();
Test::printed();
Test2::printed();*/
// 魔术方法__call 按预期工作
// PHP5 的对象新增了一个专用方法 __call(),
// 这个方法用来监视一个对象中的其它方法。如果你试着调用一个对象中不存在或被权限控制中的方法,__call 方法将会被自动调用.
/*trait Base{
public function __call($name, $arguments)
{
return count($arguments);
}
}
class TestTrait{
use Base;
}
$obj = new TestTrait();
echo $obj ->go(1,2,3);*/
// trait单例
/*trait Singleton{
public static function getSingleton(){
static $singleton = NULL;
$class = __CLASS__;
return $singleton?$singleton:new $class;
}
public function __clone() {
trigger_error('Cloning '.__CLASS__.' is not allowed.',E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Unserializing '.__CLASS__.' is not allowed.',E_USER_ERROR);
}
}
class Test{
use Singleton;
private function __construct()
{
$this ->name ='Test';
}
}
class Test2{
use Singleton;
private function __construct()
{
$this->name = 'Test2';
}
}
$test = Test::getSingleton();
var_dump($test);
//$test11 = Test::getSingleton();
//var_dump($test11);
echo $test->name;
$test2 = Test2::getSingleton();
echo $test2 ->name;
var_dump($test2);*/