PHP的上学–Traits新性情

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

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

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

Use的不同

不同use的例子

<?php
namespace Foo\Bar;
use Foo\Test;  // means \Foo\Test - the initial \ is optional
?>

<?php
namespace Foo\Bar;
class SomeClass {
    use Foo\Test;   // means \Foo\Bar\Foo\Test
}
?>

第一个use是用于 namespace 的 use Foo\Test,找到的是 \Foo\Test,第一个use 是运用1个trait,找到的是\Foo\Bar\Foo\Test。

Trait 的静态成员

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

静态变量的例证

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

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 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
在同三个类中的命名龃龉,须要接纳 insteadof 操作符来妇孺皆知钦点使用争持方法中的哪1个。

上述办法仅同意排除掉其余措施,as 操作符能够将里面1个冲突的法子以另二个称谓来引入。

争执化解的事例

<?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的点子能够被定义为在普通类的静态方法,就足以被调用

实例如下

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

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

 

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;
    }
}
?>

自 PHP 5.4.0 起,PHP 实现了代码复用的多个方法,称为 traits。

多个 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!

__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
插入的积极分子所覆盖。优先顺序是源于当前类的成员覆盖了 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 同样能够定义属性。

概念属性的事例

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

class PropertiesExample {
    use PropertiesTrait;
}

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

一经 trait
定义了1特性质,那类将不可能定义同样名称的天性,不然会发出2个张冠李戴。假设该属性在类中的定义与在
trait
中的定义包容(同样的可知性和起始值)则错误的级别是 E_STRICT,不然是一个沉重错误。

PHP,争论的事例

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

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

Trait 和三个类一般,但惟独意在用细粒度和相同的法门来构功能应。Trait
不可能经过它自个儿来实例化。它为观念三番陆次扩充了档次特性的重组;约等于说,应用类的分子不须要继续。

Traits 是一种为接近 PHP 的单继承语言而准备的代码复用机制。Trait
为了减小单继承语言的限定,使开发职员能够随意地在不相同层次结构内独立的类中复用方法集。Traits
和类组合的语义是概念了一种艺术来收缩复杂性,制止古板多延续和混入类(Mixin)相关的卓越问题。

修章的访问控制

使用 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 来组成 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!

在读书yii2源码的时候接触到了trait,就学习了眨眼之间间,写下博客记录一下。

相关文章