PHP中的traits实现代码复用使用实例_php技巧_脚本之

2019-12-18 14:23栏目:威尼斯网站

PHP5.4后新扩张traits实现代码复用机制,Trait和类日常,但不能够被实例化,无需世襲,只要求在类中接收首要词use引进就可以,可引进多个Traits,用','隔绝。

在翻阅yii2源码的时候接触到了trait,就学习了一下,写下博客记录一下。

Trait轻松利用

自 PHP 5.4.0 起,PHP 实现了代码复用的三个艺术,称为 traits。

var1; //test1$c->test2

Traits 是黄金年代种为贴近 PHP 的单世袭语言而考虑的代码复用机制。Trait 为了裁减单世袭语言的约束,使开采职员可以轻便地在差异档案的次序构造内独立的类中复用方法集。Traits 和类组合的语义是概念了黄金年代种形式来减弱复杂性,幸免守旧多三回九转和混入类(Mixin)相关的卓越难题。

预先级难点Trait会覆盖世袭的方法,当前类会覆盖Trait方法。

Trait 和叁个类经常,但唯有意在用细粒度和相像的章程来构作用应。Trait 不可能透过它自己来实例化。它为思想三回九转增加了档案的次序性格的构成;也正是说,应用类的成员不必要继续。

trait A { public $var1 = 'test'; public function test'; } public function test1'; }} class B { public function test'; } public function test1'; }}class C extends B{ use A; public function test'; }} $c = new C; //c::test; //A::test1多个Trait冲突问题如果没有解决冲突,会产生致命错误;可用insteadof来明确使用冲突中哪一个方法;可用as操作符将其中一个冲突方法另起名;trait A { public function test'; }} trait B { public function test'; }} class C { use A,B { B::test insteadof A; B::test as t; }} $c = new C; //B::test 可以用as另起名

Trait 示例

as可用来修章访谈调节

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}

class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}

class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>
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; //Fatal error: Call to protected method A::sayHello() from context ''

优先级

从基类世襲的分子被 trait 插入的积极分子所隐蔽。优先顺序是发源当前类的成员覆盖了 trait 的措施,而 trait 则覆盖了被接续的艺术。

事情发生前顺序示例

<?php
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
?>

上述例程会输出:Hello World!

从基类世襲的分子被插入的 SayWorld Trait 中的 sayHello 方法所覆盖。其作为 MyHelloWorld 类中定义的措施相通。优先顺序是现阶段类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。

另三个刚开始阶段级依次的例证

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello();
?>

如上例程会输出:Hello Universe!

Trait中使用Trait

多个 trait

透过逗号分隔,在 use 注解列出四个 trait,能够都插入到二个类中。

七个 trait 的用法的例子

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

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

class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

以上例程会输出:Hello World!

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; //test2

冲突的消灭

借使多个 trait 都插入了二个同名的措施,若无鲜明解决冲突将会时有产生三个沉重错误。

为了缓和四个 trait 在同一个类中的命名冲突,需求使用 insteadof 操作符来明确内定使用冲突方法中的哪一个。

上述措施仅允许消弭掉别的方法,as 操作符能够将中间二个冲突的方法以另一个称谓来引进。

冲突消除的事例

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    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 使用了 trait A 和 B。由于 A 和 B 有冲突的措施,其定义了应用 trait B 中的 smallTalk 乃至 trait A 中的 bigTalk。

Aliased_Talker 使用了 as 操作符来定义了 talk 来作为 B 的 bigTalk 的别名。

Trait支持抽象方法、协理静态方法、不得以一向定义静态变量,但静态变量可被trait方法援引。

纠正章程的访谈调控

使用 as 语法还足以用来调治措施的访谈调节。

改善章程的访谈调控的例证

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

// 修改 sayHello 的访问控制
class MyClass1 {
    use HelloWorld { sayHello as protected; }
}

// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化
class MyClass2 {
    use HelloWorld { sayHello as private myPrivateHello; }
}
?>
trait A { public function test1() { static $a = 0; $a  ; echo $a; } abstract public function test2(); //可定义抽象方法} class B { use A; public function test2;$b->test1; //2

从 trait 来组成 trait

正如类能够使用 trait 同样,此外 trait 也能够利用 trait。在 trait 定义时经过应用三个或多少个 trait,它能够结合此外 trait 中的部分或任何分子。

从 trait 来组成 trait的例子

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

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!

Trait可定义属性,但类中不可能定义相通名称属性

Trait 的肤浅成员

为了对运用的类施加压力实制要求,trait 帮忙抽象方法的选择。

意味着经过架空方法来张开强迫必要的事例

<?php
trait Hello {
    public function sayHelloWorld() {
        echo 'Hello'.$this->getWorld();
    }
    abstract public function getWorld();
}

class MyHelloWorld {
    private $world;
    use Hello;
    public function getWorld() {
        return $this->world;
    }
    public function setWorld($val) {
        $this->world = $val;
    }
}
?>
trait A { public $test1;} class B { use A; public $test2;}

Trait 的静态成员

Traits 能够被静态成员静态方法定义。

静态变量的例子

<?php
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c   1;
        echo "$cn";
    }
}

class C1 {
    use Counter;
}

class C2 {
    use Counter;
}

$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>

静态方法的事例

<?php
trait StaticExample {
    public static function doSomething() {
        return 'Doing something';
    }
}

class Example {
    use StaticExample;
}

Example::doSomething();
?>

静态变量和静态方法的例证

<?php
trait Counter {
    public static $c = 0;
    public static function inc() {
        self::$c = self::$c   1;
        echo self::$c . "n";
    }
}

class C1 {
    use Counter;
}

class C2 {
    use Counter;
}

C1::inc(); // echo 1
C2::inc(); // echo 1
?>

属性

Trait 相似能够定义属性。

概念属性的事例

<?php
trait PropertiesTrait {
    public $x = 1;
}

class PropertiesExample {
    use PropertiesTrait;
}

$example = new PropertiesExample;
$example->x;
?>

风流倜傥旦 trait 定义了壹本本性,那类将不可能定义相似名称的属性,不然会生出一个荒诞。固然该属性在类中的定义与在 trait 中的定义宽容(雷同的可以预知性和伊始值)则错误的等级是 E_STRICT,不然是二个致命错误。

冲突的例子

<?php
trait PropertiesTrait {
    public $same = true;
    public $different = false;
}

class PropertiesExample {
    use PropertiesTrait;
    public $same = true; // Strict Standards
    public $different = true; // 致命错误
}
?>

Use的不同

不同use的例子

<?php
namespace FooBar;
use FooTest;  // means FooTest - the initial  is optional
?>

<?php
namespace FooBar;
class SomeClass {
    use FooTest;   // means FooBarFooTest
}
?>

第一个use是用于 namespace 的 use FooTest,找到的是 FooTest,首个use 是使用三个trait,找到的是FooBarFooTest。

__CLASS__和__TRAIT__

__CLASS__ 返回 use trait 的 class name,__TRAIT__返回 trait name

事必躬亲如下

<?php
trait TestTrait {
    public function testMethod() {
        echo "Class: " . __CLASS__ . PHP_EOL;
        echo "Trait: " . __TRAIT__ . PHP_EOL;
    }
}

class BaseClass {
    use TestTrait;
}

class TestClass extends BaseClass {

}

$t = new TestClass();
$t->testMethod();

//Class: BaseClass
//Trait: TestTrait

Trait单例

实比方下

<?php

trait singleton {    
    /**
     * private construct, generally defined by using class
     */
    //private function __construct() {}

    public static function getInstance() {
        static $_instance = NULL;
        $class = __CLASS__;
        return $_instance ?: $_instance = 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);
    }
}

/**
* Example Usage
*/

class foo {
    use singleton;

    private function __construct() {
        $this->name = 'foo';
    }
}

class bar {
    use singleton;

    private function __construct() {
        $this->name = 'bar';
    }
}

$foo = foo::getInstance();
echo $foo->name;

$bar = bar::getInstance();
echo $bar->name;

调用trait方法

纵然不很分明,可是借使Trait的措施能够被定义为在普通类的静态方法,就能够被调用

实例如下

<?php 
trait Foo { 
    public static function bar() { 
        return 'baz'; 
    } 
} 

echo Foo::bar(),"\n"; 
?>

 

版权声明:本文由威尼斯网站发布于威尼斯网站,转载请注明出处:PHP中的traits实现代码复用使用实例_php技巧_脚本之