加入收藏 | 设为首页 | 会员中心 | 我要投稿 银川站长网 (https://www.0951zz.com/)- 云通信、基础存储、云上网络、机器学习、视觉智能!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP使用traits实现代码复用的案例

发布时间:2023-05-20 12:54:36 所属栏目:PHP教程 来源:
导读:PHP 5.4中的traits,是新引入的特性,用于实现代码重用的方法,下面我们就一起来看看PHP使用traits实现代码复用的例子,希望文章可以帮助到各位.PHP5.4后新增traits实现代码复用机制,Trait和类相似,但不能被实例化,无需继

PHP 5.4中的traits,是新引入的特性,用于实现代码重用的方法,下面我们就一起来看看PHP使用traits实现代码复用的例子,希望文章可以帮助到各位.

PHP5.4后新增traits实现代码复用机制,Trait和类相似,但不能被实例化,无需继承,只需要在类中使用关键词use引入即可,可引入多个Traits,用','隔开.

(1)Trait简单使用

<?php 

trait A { 

    public $var1 = 'test1'; 

    public function test1() { 

        echo 'trait A::test1()'; 

    } 

trait B { 

    public $var2 = 'test2'; 

    public function test2() { 

        echo 'trait B::test2()'; 

    } 

class C { 

    use A,B; 

$c = new C(); 

echo $c->var1; //test1 

$c->test2(); //trait B::test2() 

?> 

(2)优先级问题

Trait会覆盖继承的方法,当前类会覆盖Trait方法.

trait A { 

    public $var1 = 'test'; 

    public function test() { 

        echo 'A::test()'; 

    } 

    public function test1() { 

        echo 'A::test1()'; 

    } 

class B { 

    public function test() { 

        echo 'B::test()'; 

    } 

    public function test1() { 

        echo 'B::test1()'; 

    } 

class C extends B{ 

    use A; 

    public function test() { 

        echo 'c::test()'; 

    } //开源软件:Cuoxin.com 

$c = new C(); 

$c->test(); //c::test() 

$c->test1(); //A::test1() 

(3)多个Trait冲突问题

如果没有解决冲突,会产生致命错误,可用insteadof来明确使用冲突中哪一个方法,可用as操作符将其中一个冲突方法另起名.

trait A { 

    public function test() { 

        echo 'A::test()'; 

    } 

trait B { 

    public function test() { 

        echo 'B::test()'; 

    } 

class C { 

    use A,B { 

        B::test insteadof A; 

        B::test as t; 

    } 

$c = new C(); 

$c->test(); //B::test() 

$c->t(); //B::test()   可以用as另起名 

(4)as可用来修改方法访问控制

trait  HelloWorld  { 

    public function  sayHello () { 

        echo  'Hello World!' ; 

    } 

// 修改 sayHello 的访问控制 

class  A  { 

    use  HelloWorld  {  sayHello  as protected; } 

// 给方法一个改变了访问控制的别名 

// 原版 sayHello 的访问控制则没有发生变化 

class  B  { 

    use  HelloWorld  {  sayHello  as private  myPrivateHello ; } 

$b = new A(); 

$b->sayHello(); //Fatal error: Call to protected method A::sayHello() from context '' 

(5)Trait中使用Trait

trait A { 

    public function test1() { 

        echo 'test1'; 

    } 

trait B { 

    public function test2() { 

        echo 'test2'; 

    } 

 

trait C { 

    use A,B; 

 

class D { 

    use C; 

 

$d = new D(); 

$d->test2();  //test2 

(6)Trait支持抽象方法、支持静态方法、不可以直接定义静态变量,但静态变量可被trait方法引用.

trait A { 

    public function test1() { 

        static $a = 0; 

        $a++; 

        echo $a; 

    } 

    abstract public function test2(); //可定义抽象方法 

class B { 

    use A; 

    public function test2() { 

    } 

$b = new B(); 

$b->test1(); //1 

$b->test1(); //2 

(7)Trait可定义属性,但类中不能定义同样名称属性.

trait A { 

   public $test1; 

class B { 

    use A; 

    public $test2; 

接着看.

<?php 

    trait Drive { 

        public $carName = 'trait'; 

        public function driving() { 

            echo "driving {$this->carName}\n"; 

        } 

    } 

    class Person { 

        public function eat() { 

            echo "eat\n"; 

        } 

    } 

    class Student extends Person { 

        use Drive; 

        public function study() { 

            echo "study\n"; 

        } 

    } 

    $student = new Student(); 

    $student->study(); 

    $student->eat(); 

    $student->driving(); 

//输出结果如下: 

study 

eat 

driving trait 

上面的例子中,Student类通过继承Person,有了eat方法,通过组合Drive,有了driving方法和属性carName.

如果Trait、基类和本类中都存在某个同名的属性或者方法,最终会保留哪一个呢?通过下面的代码测试一下:

<?php  

    trait Drive { 

        public function hello() { 

            echo "hello drive\n"; 

        } 

        public function driving() { 

            echo "driving from drive\n"; 

        } 

    } 

    class Person { 

        public function hello() { 

            echo "hello person\n"; 

        } 

        public function driving() { 

            echo "driving from person\n"; 

        } 

    } 

    class Student extends Person { 

        use Drive; 

        public function hello() { 

            echo "hello student\n"; 

        } 

    } 

    $student = new Student(); 

    $student->hello(); 

    $student->driving(); 

//输出结果如下: 

hello student 

driving from drive 

因此得出结论:当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,而 trait 的方法又覆盖了基类中的方法.

如果要组合多个Trait,通过逗号分隔 Trait名称:use Trait1, Trait2;

如果多个Trait中包含同名方法或者属性时,会怎样呢?答案是当组合的多个Trait包含同名属性或者方法时,需要明确声明解决冲突,否则会产生一个致命错误.

<?php 

trait Trait1 { 

    public function hello() { 

        echo "Trait1::hello\n"; 

    } 

    public function hi() { 

        echo "Trait1::hi\n"; 

    } 

trait Trait2 { 

    public function hello() { 

        echo "Trait2::hello\n"; 

    } 

    public function hi() { 

        echo "Trait2::hi\n"; 

    } 

class Class1 { 

    use Trait1, Trait2; 

//输出结果如下: 

PHP Fatal error:  Trait method hello has not been applied, because there are collisions with other trait methods on Class1 in ~/php54/trait_3.php on line 20 

使用insteadof和as操作符来解决冲突,insteadof是使用某个方法替代另一个,而as是给方法取一个别名,具体用法请看代码:

<?php 

trait Trait1 { 

    public function hello() { 

        echo "Trait1::hello\n"; 

    } 

    public function hi() { 

        echo "Trait1::hi\n"; 

    } 

trait Trait2 { 

    public function hello() { 

        echo "Trait2::hello\n"; 

    } 

    public function hi() { 

        echo "Trait2::hi\n"; 

    } 

class Class1 { 

    use Trait1, Trait2 { 

        Trait2::hello insteadof Trait1; 

        Trait1::hi insteadof Trait2; 

    } 

class Class2 { 

    use Trait1, Trait2 { 

        Trait2::hello insteadof Trait1; 

        Trait1::hi insteadof Trait2; 

        Trait2::hi as hei; 

        Trait1::hello as hehe; 

    } 

$Obj1 = new Class1(); 

$Obj1->hello(); 

$Obj1->hi(); 

echo "\n"; 

$Obj2 = new Class2(); 

$Obj2->hello(); 

$Obj2->hi(); 

$Obj2->hei(); 

$Obj2->hehe(); 

//输出结果如下: 

Trait2::hello 

Trait1::hi 

Trait2::hello 

Trait1::hi 

Trait2::hi 

Trait1::hello 

as关键词还有另外一个用途,那就是修改方法的访问控制:

<?php 

    trait Hello { 

        public function hello() { 

            echo "hello,trait\n"; 

        } 

    } 

    class Class1 { 

        use Hello { 

            hello as protected; 

        } 

    } 

    class Class2 { 

        use Hello { 

            Hello::hello as private hi; 

        } 

    } 

    $Obj1 = new Class1(); 

    $Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的 

    $Obj2 = new Class2(); 

    $Obj2->hello(); # 原来的hello方法仍然是公共的 

    $Obj2->hi();  # 报致命错误,因为别名hi方法被修改成私有的 

?> 

Trait 也能组合Trait,Trait中支持抽象方法、静态属性及静态方法,测试代码如下:

<?php 

trait Hello { 

    public function sayHello() { 

        echo "Hello\n"; 

    } 

trait World { 

    use Hello; 

    public function sayWorld() { 

        echo "World\n"; 

    } 

    abstract public function getWorld(); 

    public function inc() { 

        static $c = 0; 

        $c = $c + 1; 

        echo "$c\n"; 

    } 

    public static function doSomething() { 

        echo "Doing something\n"; 

    } 

class HelloWorld { 

    use World; 

    public function getWorld() { 

        return 'get World'; 

    } 

$Obj = new HelloWorld(); 

$Obj->sayHello(); 

$Obj->sayWorld(); 

echo $Obj->getWorld() . "\n"; 

HelloWorld::doSomething(); 

$Obj->inc(); 

$Obj->inc(); 

//输出结果如下: 

Hello 

World 

get World 

Doing something 

?>

(编辑:银川站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!