[PHP] 이럴 때 어떡해?trait 편

13803 단어 PHP
이럴 땐 어떡해?나는 이 문제를 해결해야 한다고 생각했다.
우선trait편이다.
후속이 있을지 모르겠다.

컨디션


환경OS는 Ubuntu, PHP는 7.0입니다.
% php -v
PHP 7.0.22-0ubuntu0.17.04.1 (cli) (built: Aug  8 2017 22:03:30) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.22-0ubuntu0.17.04.1, Copyright (c) 1999-2017, by Zend Technologies

같은 이름 방법을 정의한 여러 Trait 사용


전제 조건


예를 들어 같은 이름say을 가진 Trait가 있다.
A.php
trait A
{
    public function say()
    {
        echo "I am A\n";
    }
}
B.php
trait B
{
    public function say()
    {
        echo "I am B\n";
    }
}

문제.


간단히use 트래잇 두 개면...
Sayer.php
class Sayer
{
    use A, B;
}
Fatal 오류가 발생했습니다.
PHP Fatal error:  Trait method say has not been applied, because there are collisions with other trait methods on Sayer

해결 방법(1) - Trait 하나만 사용하면 되는 경우

insteadof를 사용하여 B 대신 "A"를 사용하도록 지시합니다.
Sayer.php
class Sayer
{
    use A, B {
        A::say insteadof B;
    }
}
usage
$sayer = new Sayer();
$sayer->say();
# 実行結果:
# I am A

솔루션(2) - 모든 Trait를 사용하려는 경우

as 다른 이름을 지어라.
Sayer.php
class Sayer
{
    use A, B {
        A::say as sayA;
        B::say as sayB;
    }

    public function say()
    {
        $this->sayA();
        $this->sayB();
    }
}
usage
$sayer = new Sayer();
$sayer->say();
# 実行結果:
# I am A
# I am B

기본 클래스와 같은 이름을 정의하는 Trait 사용하기


전제 조건


이런 기초반과 트레잇이 있다.모두 say 방법이 있다.
Base.php
class Base
{
    public function say()
    {
        echo "I am Base\n";
    }
}
A.php
trait A
{
    public function say()
    {
        echo "I am A\n";
    }
}
상속과 Trait를 사용했습니다.
Sayer.php
class Sayer extends Base
{
    use A;
}

문제.


기본 클래스가 아니라 Trait입니다.
usage
$sayer = new Sayer();
$sayer->say();
# 実行結果:
# I am A

해결책


Trait은 별칭으로 다시 작성됩니다.
Sayer.php
class Sayer extends Base
{
    use A {
        A::say as sayA;
    }

    public function say()
    {
        parent::say();
    }
}
usage
$sayer = new Sayer();
$sayer->say();
# 実行結果:
# I am Base

잘못된 해결 방법


그냥 별명만 붙인다면 트레이트라고 해.
Sayer.php
class Sayer extends Base
{
    use A {
        A::say as sayA;
    }
}
usage
$sayer = new Sayer();
$sayer->say();
$sayer->sayA();
# 実行結果:
# I am A
# I am A

같은 이름의 속성 (구성원 변수) 을 정의한trait 사용하기


전제 조건


예를 들어, 두 개의 속성이 private $__cache인trait이다.
Mars.php
trait Mars
{
    private $__cache;

    /**
     * 火星からのメッセージを読み込みます(キャッシュ付き)
     */
    public function loadMessageFromMars()
    {
        if (!empty($this->__cache)) {
            return $this->__cache;
        }

        $message = 'Message from Mars.';
        $this->__cache = $message;

        return $this->__cache;
    }
}
Neptune.php
trait Neptune
{
    private $__cache;

    /**
     * 海王星からメッセージを読み込みます(キャッシュ付き)
     */
    public function loadMessageFromNeptune()
    {
        if (!empty($this->__cache)) {
            return $this->__cache;
        }

        $message = 'Love Letter from Neptune.';
        $this->__cache = $message;

        return $this->__cache;
    }
}
이 두 개의trait를 사용하는 클래스를 정의했습니다.
MessageAggregator.php
class MessageAggregator
{
    use Mars, Neptune;

    public function loadMessages() {
        yield $this->loadMessageFromMars();
        yield $this->loadMessageFromNeptune();
    }
}

문제.


시행해 보다.
$aggregator = new MessageAggregator();

foreach ($aggregator->loadMessages() as $i) {
    echo $i, "\n";
}
실행 결과
Message from Mars.
Message from Mars.
그거!?
해왕성에서 온 메시지가 어디로 갔는지 모르겠다.
분명히 러브레터를 받았어야 했는데

해결책


아쉽게도 없습니다.
받아야 할 연서가 어둠 속에 있다.
그걸 토대로 헤어져서...

해결할 수 없는 방법


우리 코드 장정을 정비합시다.
  • trait에서 속성을 정의하지 않음
  • 외부로부터trait
  • 사용하지 않음

    좋은 웹페이지 즐겨찾기