PHP中traits的作用和使用(PHP trait)

网友投稿 291 2022-07-25

traits是在5.4中新增的一个用于实现代码重用的方法。

php是一种单一继承的语言,我们无法像java一样在一个class中extends多个基类来实现代码重用,现在Traits能解决这一代码重用的问题,它能让开发者在多个不同的class中实现代码重用。

Traits和class在语义的定义上都是为了减少代码的复杂性,避免多重继承的问题。

Traits 和class相似,但是仅用于以统一和较细粒度的方式来提供一组功能,在Traits内部无法进行实例化,即不存在类似class的构造函数__construct()。Traits作为一个php传统继承的扩展并实现水平集成;因此,在应用程序的class中可以不再需要继承。

1)如何使用

在类中用关键字'use' 来引用 Traits。多个Traits 用','隔开。

实例代码如下:

} function getReturnDescription() {

}

}class ezcReflectionMethod extends ReflectionMethod { use ezcReflectionReturnInfo; /* ... */ } class ezcReflectionFunction extends ReflectionFunction { use ezcReflectionReturnInfo; /* ... */ } ?>

2)优先级

基类中的成员函数将被Traits中的函数覆盖,当前类中的成员函数将覆盖Traits中的函数。

    public function sayHello() {

        echo 'Hello ';

    }

} trait SayWorld {

    public function sayHello() {

        parent::sayHello();

        echo "World!\n";

    }

} class MyHelloWorld extends Base {

    use SayWorld;

} class MyHelloWorldExt extends Base {

    use SayWorld;

    public function sayHello() {

        /**

         * 这里是5.4中的新的改动,5.4之前的版本会提示:

         * PHP Fatal error:  Cannot use string offset as an array

         * 5.4中改进为返回字符串中的该索引号的字符

         */         $str  = "Arvin";

        echo $str[0][0];// echo 'A';     }

    public function shortArray() {

        $array = ['first', 2, 3, 4];//5.4中的数组简单语法         echo $array[0];//5.4中的数组解引用取数组元素方法     }

}

$o = new MyHelloWorld();

$o->sayHello();

$oe = new MyHelloWorldExt();

$oe->sayHello(); echo "\n";

$oe->shortArray();

输出:

Hello World!

A

first

3)多Traits

多个Traits可以添加到一个class的声明中,多个Traits之间用","隔开。

    public function sayHello() {

        echo 'Hello ';

    }

} trait World {

    public function sayWorld() {

        echo 'World';

    }

} class MyHelloWorld {

    use Hello, World;

}

$o = new MyHelloWorld();

$o->sayHello();

$o->sayWorld();

输出结果:

Hello World

4)多Traits冲突

如果添加到同一个class的两个Traits中有相同的函数名称,且没有明确的进行处理,将产生一个错误。

为了解决同一个类中两个Tratis中的同名函数冲突,需要用insteadof操作符来选择正确的函数。

因为方法的唯一性和排他性,'as'操作符允许用在冲突函数之后以解决内部冲突的问题。

} public function bigTalk() { echo 'A';

}

} trait B { public function smallTalk() { echo 'b';

} public function bigTalk() { echo 'B';

}

} class Talker { use A, B { B::smallTalk insteadof A;

A::bigTalk insteadof B;

}

} class Aliased_Talker { use A, B { B::smallTalk insteadof A;

A::bigTalk insteadof B;

B::bigTalk as talk;

}

}

上面的例子中,Talker使用Traits A 和B,因此两者中相同的函数名称存在冲突。

alker中定义了smallTalk取自Traits B,bigTalk取自Traits A。

Aliased_Talker中通过使用as操作符来确保Traits B中的bigTalk通过别名talk来实现。

5)改变函数访问权限

我们可以使用as语法来改变Traits中函数的访问权限属性。

}

} // Change visibility of sayHello,改变sayHello的访问权限。 class MyClass1 { use HelloWorld { sayHello as protected; }

} // Alias method with changed visibility // sayHello visibility not changed,设置别名myPrivateHello。 class MyClass2 { use HelloWorld { sayHello as private myPrivateHello; }

}

6)Traits组成新Traits

就像许多类一样可以在类中使用Traits,Traits中一样可以使用Traits。可以在一个Traits中定义一个或者多个Traits,这些Traits 可以作为部分或者全部成员被定义在其他Traits中。

}

} trait World { public function sayWorld() { echo 'World!';

}

} trait HelloWorld { use Hello, World;

} class MyHelloWorld { use HelloWorld;

}

$o = new MyHelloWorld();

$o->sayHello();

$o->sayWorld();

以上例程会输出:Hello World!

7)抽象Trait成员

为了在类中强制实现某些方法,可以在Traits中使用抽象方法。

例如:

    public function sayHelloWorld() {

        echo 'Hello '.$this->getWorld();

    }

    abstract public function getWorld();

} class MyHelloWorld {

    private $world;

    use Hello;

    public function __construct($world) {

        $this->world = $world;

    }

    public function getWorld() {

        return $this->world;

    }

} /**

 * 这里用到了5.4新功能 类实例化解引用操作

 * (new class())->method();

 */ (new MyHelloWorld('Arvin'))->sayHelloWorld(); ?> 该实例输出:

Hello Arvin

8)静态Trait成员

在Traits中不能定义static 静态变量,但是可以定义在Tratis的函数中。Tratis中同样可以定义静态函数。

    public function inc() {

        static $c = 0;//静态变量         $c += 1;

        echo "$c\n";

    }

    /**

     * 静态方法

     */     public static function doSomething() {

        echo 'Doing something';

    }

} class C1 {

    use Counter;

}

(new C1())->inc(); // echo 1 C1::doSomething(); ?> 输出为:

1

Doing something

9) Traits 定义属性

如果在一个trait中定义了一个属性,则在引用该trait的类中不能定义同名的属性,如果该类中定义有和trait中已定义属性具有相同的名字和访问可见性,则是一个E_STRICT 提示,否则抛出语法错误。

    public $x = 1;

    public $y = 2;

} class PropertiesExample {

    use PropertiesTrait;

    public $x = 1;

    //public $y = 3; }

$example = new PropertiesExample; echo $example->x, $example->y; ?> 输出:

12

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:经典面试题:如何保证缓存与数据库的双写一致性?(缓存和数据库一致性面试题)
下一篇:除了负载均衡,Nginx还可以做很多,限流、缓存、黑白名单等(nginx 限流 友好提示)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~