[php] PHP Trait이 인터페이스를 구현할 수없는 이유는 무엇입니까?

PHP Trait (PHP 5.4)가 인터페이스를 구현할 수없는 이유가 궁금합니다.

user1460043의 답변에서 업데이트 => … 특정 인터페이스를 구현하는 데 사용하는 클래스가 필요하지 않습니다.

나는 사람들이이 경우에 있다고 생각할 수 있기 때문에, 분명이 될 수 있음을 이해 Class A사용 Trait T를 구현하는이 interface I(가)보다, Class A이행되어야한다 interface Iundirectly을 (이 사실 때문에없는 Class A특성 방법의 이름을 바꿀 수있다).

제 경우에는 특성을 사용하는 클래스가 구현하는 인터페이스에서 메서드를 호출하는 특성이 있습니다.

특성은 사실 인터페이스의 일부 메소드의 구현입니다. 그래서 저는 제 특성을 사용하려는 모든 클래스가 인터페이스를 구현해야하는 코드를 “디자인”하고 싶습니다. 그러면 Trait이 인터페이스에 의해 정의 된 클래스 메서드를 사용하고 클래스에 존재하는지 확인할 수 있습니다.



답변

정말 짧은 버전은 할 수 없기 때문에 더 간단합니다. 그것은 특성이 작동하는 방식이 아닙니다.

use SomeTrait;PHP로 작성할 때 (효과적으로) 컴파일러에게 Trait의 코드를 복사하여 사용중인 클래스에 붙여 넣도록 지시합니다.

use SomeTrait;는 클래스 내부에 있기 때문에 implements SomeInterface클래스 외부에 있어야하므로 클래스에 추가 할 수 없습니다 .

“PHP에 특성 유형이없는 이유는 무엇입니까?”

인스턴스화 할 수 없기 때문입니다. 트레이 트는 코드에서 참조 할 수있는 객체 나 유형 이 아니라 실제로 언어 구조 (컴파일러에게 트레이 트 코드를이 클래스에 복사하여 붙여 넣도록 지시)에 불과합니다 .

그래서 저는 제 특성을 사용하려는 모든 클래스가 인터페이스를 구현해야하는 코드를 “디자인”하고 싶습니다.

추상 클래스를 사용 use하여 특성에 적용한 다음 클래스를 확장 할 수 있습니다.

interface SomeInterface{
    public function someInterfaceFunction();
}

trait SomeTrait {
    function sayHello(){
        echo "Hello my secret is ".static::$secret;
    }
}

abstract class AbstractClass implements SomeInterface{
    use SomeTrait;
}

class TestClass extends AbstractClass {
    static public  $secret = 12345;

    //function someInterfaceFunction(){
        //Trying to instantiate this class without this function uncommented will throw an error
        //Fatal error: Class TestClass contains 1 abstract method and must therefore be 
        //declared abstract or implement the remaining methods (SomeInterface::doSomething)
    //}
}

$test = new TestClass();

$test->sayHello();

그러나-Trait을 사용하는 모든 클래스가 특정 메서드를 갖도록 강요해야하는 경우, 처음에 추상 클래스 여야했던 트레이 트를 사용하고있을 수 있습니다.

또는 논리가 잘못되었다는 것입니다. 인터페이스를 구현하는 클래스에는 특정 기능이 있어야하며, 특정 기능이있는 경우 인터페이스를 구현하는 것으로 선언해야하는 것이 아닙니다.

편집하다

실제로 Traits 내부에 추상 함수를 정의하여 클래스가 메서드를 구현하도록 할 수 있습니다. 예 :

trait LoggerTrait {

    public function debug($message, array $context = array()) {
        $this->log('debug', $message, $context);
    }

    abstract public function log($level, $message, array $context = array());
}

그러나 이것은 여전히 ​​특성에서 인터페이스를 구현하는 것을 허용하지 않으며, 클래스가 이행해야하는 계약을 정의 할 때 특성보다 인터페이스가 훨씬 낫기 때문에 여전히 나쁜 디자인처럼 냄새가납니다.


답변

있다 RFC는 : 인터페이스 특색가 언어에 추가 할 다음과 같은 제안 :

trait SearchItem implements SearchItemInterface
{
    ...
}

인터페이스에 필요한 메서드는 트레이 트에 의해 구현되거나 추상으로 선언 될 수 있으며,이 경우 트레이 트를 사용하는 클래스가이를 구현할 것으로 예상됩니다.

이 기능은 현재 해당 언어에서 지원되지 않지만 검토 중입니다 (RFC의 현재 상태 : 논의 중 ).


답변

[…] 내 특성을 사용하려는 모든 클래스가 인터페이스를 구현해야하는 코드에서 “디자인”합니다. 그러면 Trait이 인터페이스에 의해 정의 된 클래스 메서드를 사용하고 클래스에 존재하는지 확인할 수 있습니다.

이것은 매우 합리적으로 들리며 귀하의 디자인에 문제가 있다고 말하지 않습니다. 이 아이디어를 염두에두고 특성이 제안되었습니다. 여기에서 두 번째 요점을 참조하십시오.

  • 트레이 트는 동작을 구현하는 일련의 메서드를 제공 합니다.
  • 트레이 트 에는 제공된 동작에 대한 매개 변수 역할을하는 메소드 세트가 필요 합니다.
  • […]

Schärli et al, Traits : Composable Units of Behaviour, ECOOP’2003, LNCS 2743, pp. 248–274, Springer Verlag, 2003, 페이지 2

따라서 특성이 인터페이스를 “구현”하는 것이 아니라 필요 로한다고 말하는 것이 더 적절할 것입니다.

PHP에서이 “특성 (소비자 클래스가 인터페이스를 구현해야 함)을 필요로한다”는 것이 불가능한 이유는 모르겠지만 현재는 누락 된 것 같습니다.

@Danack이 그의 답변 에서 언급했듯이, 트레이 트에서 추상 함수를 사용 하여 트레이 트 를 사용하는 클래스에서 “요구”할 수 있습니다. 불행히도 개인 기능으로 는 이것을 할 수 없습니다 .


답변

@Danack의 응답에 동의하지만 조금 보완하겠습니다.

정말 짧은 버전은 할 수 없기 때문에 더 간단합니다. 그것은 특성이 작동하는 방식이 아닙니다.

나는 당신이 요청한 것이 필요하고 언어 실패보다 디자인 문제로 더 명백한 경우를 거의 생각할 수 없습니다. 다음과 같은 인터페이스가 있다고 상상해보십시오.

interface Weaponize
{
    public function hasAmmunition();
    public function pullTrigger();
    public function fire();
    public function recharge();
}

인터페이스에 정의 된 함수 중 하나를 구현 하는 특성 이 생성 되었지만 프로세스에서 인터페이스에 의해 정의 된 다른 함수도 사용 하는 특성 이 생성되었습니다. 해당 기능 을 사용하는 클래스가 인터페이스를 구현하지 않으면 모든 기능이 방아쇠

trait Triggerable
{
    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}

class Warrior
{
    use Triggerable;
}

쉬운 해결책은 단순히 특성 을 사용하는 클래스가 이러한 기능을 구현하도록하는 것입니다.

trait Triggerable
{
    public abstract function hasAmmunition();
    public abstract function fire();

    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}

따라서 특성인터페이스 에 완전히 의존하는 것이 아니라 해당 기능 중 하나를 구현하기위한 제안입니다. 특성을 사용할 때 클래스는 추상 메서드의 구현을 요구하기 때문입니다.

최종 디자인

interface Weaponize
{
    public function hasAmmunition();
    public function pullTrigger();
    public function fire();
    public function recharge();
}

trait Triggerable
{
    public abstract function hasAmmunition();
    public abstract function fire();

    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}


class Warrior implements Weaponize
{
    use Triggerable;

    public function hasAmmunition()
    {
        // TODO: Implement hasAmmunition() method.
    }

    public function fire()
    {
        // TODO: Implement fire() method.
    }

    public function recharge()
    {
        // TODO: Implement recharge() method.
    }
}

제 영어 실례합니다


답변