PHP 코드 재 활용 방법 traits 새로운 기능

yii 2 소스 코드 를 읽 을 때 trait 를 접 하고 공 부 를 했 습 니 다.블 로그 기록 을 써 보 세 요.
PHP 5.4.0 부터 PHP 는 코드 를 재 활용 하 는 방법 을 실현 하여 traits 라 고 합 니 다.
Traits 는 PHP 와 유사 한 단일 계승 언어 를 위 한 코드 재 활용 메커니즘 이다.Trait 는 단일 계승 언어의 제한 을 줄 이기 위해 개발 자 들 이 서로 다른 차원 의 구조 에서 독립 된 유형 에서 자 유 롭 게 재 활용 방법 집 을 사용 할 수 있 도록 한다.Traits 와 클래스 조합의 의 미 는 복잡성 을 줄 이 고 전통 적 인 다 중 계승 과 혼합 류(Mixin)와 관련 된 전형 적 인 문 제 를 피 하 는 방식 을 정의 한 것 이다.
Trait 는 하나의 클래스 와 비슷 하지만 입자 와 일치 하 는 방식 으로 기능 을 조합 하 는 데 목적 을 둔다.Trait 는 그 자 체 를 통 해 예화 할 수 없습니다.그것 은 전통 적 인 계승 을 위해 수평 특성의 조합 을 증가 시 켰 다.애플 리 케 이 션 멤버 는 물 려 받 을 필요 가 없다 는 것 이다.
Trait 예제

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>
우선 순위
기본 클래스 에서 물 려 받 은 멤버 는 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!
기본 클래스 에서 물 려 받 은 멤버 들 이 삽 입 된 Say World 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
쉼표 로 구분 하여 use 성명 에 여러 개의 trait 를 표시 하면 하나의 클래스 에 삽입 할 수 있 습 니 다.
여러 traint 의 용법 의 예

<?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 가 같은 이름 의 방법 을 삽입 했다 면 충돌 을 명확 하 게 해결 하지 않 으 면 치 명 적 인 오류 가 발생 할 것 이다.
여러 개의 trait 가 같은 클래스 에서 의 이름 충돌 을 해결 하기 위해 서 는 인 스 테 드 of 연산 자 를 사용 하여 충돌 방법 중 어느 것 을 사용 하 는 지 명확 하 게 지정 해 야 합 니 다.
이상 의 방식 은 다른 방법 만 제외 할 수 있 습 니 다.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;
    }
}
?>
이 사례 에서 토 커 는 trait A 와 B 를 사용 했다.A 와 B 가 충돌 하 는 방법 으로 trait B 의 smallTalk 와 trait A 의 bigTalk 를 사용 하 는 것 을 정의 했다.
Aliased_토 커 는 as 연산 자 를 사용 해 토 크 를 B 의 빅 토 크 라 는 별명 으로 정의 했다.
수정 방법의 접근 제어
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!
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 의 정적 멤버
Traits 는 정적 구성원 의 정적 방법 에 의 해 정 의 될 수 있 습 니 다.
정적 변수의 예

<?php
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c + 1;
        echo "$c
";
    }
}
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 . "
";
    }
}
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 입 니 다.STRCT,그렇지 않 으 면 치 명 적 인 오류 입 니 다.
충돌 의 예

<?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 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 는 trait 를 사용 합 니 다.찾 은 것 은\Foo\Bar\Foo\Test 입 니 다.
__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 {
    function bar() {
        return 'baz';
    }
}
echo Foo::bar(),"\
";
?>
젊은이 들 은 traits 의 새로운 특성 에 대해 잘 알 고 있 습 니까?본 고 는 여러분 에 게 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기