php中的trait

PHP5.4起,新增一种新的代码复用的方法,trait。PHP与JAVA类似,与C++不同,是一种单继承语言,PHP引入trait,可以减少单继承语言的限制,使开发人员能够自由地在不同的层次结构内独立的类中复用method。Trait和Class组合的语义定义了一种减少复杂性的方式,避免传统多继承和Mixin类相关经典问题,例如C++中的钻石危机(也称棱形问题):
  1. 如果在一个子类继承的多个父类中拥有相同名字的实例变量,子类在引用该变量时将产生歧义,无法判断应该使用哪个父类的变量。
  2. 如果在一个子类继承的多个父类中拥有相同方法,子类中有没有覆盖该方法,那么调用该方法时将产生歧义,无法判断应该调用哪个父类的方法。

Trait和Class相似,但仅仅旨在用细粒度和一致的方式来组合功能。无法通过trait自身来实例化。它为传统继承增加了水平特性的组合。

Trait使用case

<?php

trait Mytrait {
    public $a = 100;
    public function test1() {
        echo "Mytrait Test1\n";
    }   
    public static function test2() {
        echo "Mytrait Test2\n";
    }   

}

class TraitExample1 {
    use Mytrait;
}

$obj = new TraitExample1();
$obj->test1();
TraitExample1::test2();
echo $obj->a . "\n";

优先级

对于方法:
当前类的成员>trait的方法>从基类继承的成员

对于变量:
当前类和基类中如果定义了trait同名的变量,如果该变量的定义兼容(同样的可见性及初始值)错误级别是E_STRICT,否则错误级别是E_ERROR.。


<?php

trait Mytrait {
    public $a = 100;
    public function test1() {
        echo "Mytrait Test1\n";
    }   
    public static function test2() {
        echo "Mytrait Test2\n";
    }   

}
class Base {
    public function test1() {
        echo "Base Test1\n";
    }   
    public static function test2() {
        echo "Base Test2\n";
    }   
    public static function test3() {
        echo "Base Test3\n";
    }   
    
}
class TraitExample1 extends Base{
    use Mytrait;
    public function test1() {
        echo "TraitExample1 Test1\n";
    }   

}

$obj = new TraitExample1();
$obj->test1();
TraitExample1::test2();
$obj->test3();
echo $obj->a . "\n";

多个trait

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

如果两个trait都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。为了解决多个trait在同一个类中的命名冲突,需要使用insteadof操作符来明确指定使用冲突方法中的哪一个。或者使用as操作符,可以将其中一个冲突的方法以另一个名称来引入。

同样的,如果两个trait有同名的变量,如果该变量的定义兼容(同样的可见性及初始值)错误级别是E_STRICT,否则错误级别是E_ERROR.

且不能通过解决方法冲突的方式解决。

<?php

trait Mytrait {
    public $a = 100;
    public function test1() {
        echo "Mytrait Test1\n";
    }   
    public static function test2() {
        echo "Mytrait Test2\n";
    }   

}
trait Mytrait2 {
    public function test1() {
        echo "Mytrait2 Test1\n";
    }   
    public static function test2() {
        echo "Mytrait2 Test2\n";
    }   

}
class TraitExample1{
    use Mytrait,Mytrait2 {
        Mytrait::test1 insteadof Mytrait2;
        Mytrait2::test2 insteadof Mytrait;
        Mytrait::test2 as test2_2;
    }   
}

$obj = new TraitExample1();
$obj->test1();
TraitExample1::test2();
$obj->test2_2();
echo $obj->a . "\n";

修改方法的访问控制

<?php

trait Mytrait {
    public function test1() {
        echo "Mytrait Test1\n";
    }   
    public function test2() {
        echo "Mytrait Test2\n";
    }   
    private function test3() {
        echo "Mytrait Test3\n";
    }   

}
class TraitExample1{
    use Mytrait {
        test1 as protected;
        test2 as public test2_1;
        test3 as public;
    }   
}

指定alias会创建一个新的方法,原方法访问控制权限不变。不仅可以缩小权限的方向修改(public->private),也可以向放大权限的修改(private->public).


从trait来组成trait

与Class中使用多个trait类似,trait也可以使用多个trait。冲突的解决方式也一致。

<?php

trait Mytrait {
    public function test1() {
        echo "Mytrait Test1\n";
    }   
    public function test2() {
        echo "Mytrait Test2\n";
    }   

}
trait Mytrait2 {
    public function test1() {
        echo "Mytrait2 Test1\n";
    }   
    public function test2() {
        echo "Mytrait2 Test2\n";
    }   

}

trait Mytrait3 {
    use Mytrait, Mytrait2 {
        Mytrait::test1 insteadof Mytrait2;
        Mytrait2::test2 insteadof Mytrait;
    }   
}
class TraitExample1{
    use Mytrait3;
}

$obj = new TraitExample1();
$obj->test1();
$obj->test2();

Trait的抽象成员

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

Trait的静态成员

trait可以定义静态变量,静态方法。

<?php

trait Mytrait {
    public static $in = 10; 
    public function test1() {
        echo "Mytrait Test1\n";
    }   
    public function test2() {
        echo "Mytrait Test2\n";
    }   

}
trait Mytrait2 {
    public function test1() {
        echo "Mytrait2 Test1\n";
    }   
    public static function test2() {
        echo "Mytrait2 Test2\n";
    }   

}

trait Mytrait3 {
    use Mytrait, Mytrait2 {
        Mytrait::test1 insteadof Mytrait2;
        Mytrait::test2 insteadof Mytrait2;
        Mytrait2::test2 as test3;
    }   
}
class TraitExample1{
    use Mytrait3;
}

$obj = new TraitExample1();
$obj->test1();
$obj->test2();
TraitExample1::test3();
[root@hadoop1 php]# cat trait2.php    
<?php

trait Mytrait {
        public static $in = 10;
        public function test1() {
                echo "Mytrait Test1\n";
        }
        public function test2() {
                echo "Mytrait Test2\n";
        }

}
trait Mytrait2 {
        public function test1() {
                echo "Mytrait2 Test1\n";
        }
        public static function test2() {
                echo "Mytrait2 Test2\n";
        }

}

trait Mytrait3 {
        use Mytrait, Mytrait2 {
                Mytrait::test1 insteadof Mytrait2;
                Mytrait::test2 insteadof Mytrait2;
                Mytrait2::test2 as test3;
        }
}
class TraitExample1{
        use Mytrait3;
}

$obj = new TraitExample1();
$obj->test1();
$obj->test2();
TraitExample1::test3();
echo TraitExample1::$in;












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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值