Program Tip

PHP 7 인터페이스, 반환 유형 힌트 및 자체

programtip 2020. 11. 5. 18:51
반응형

PHP 7 인터페이스, 반환 유형 힌트 및 자체


PHP 7에서 반환 유형 힌팅을 사용하는 데 문제가 생겼습니다. 내 이해는 힌팅 : self이 구현 클래스가 자체적으로 반환하도록 의도한다는 것을 의미한다는 것입니다. 따라서 나는 그것을 : self나타 내기 위해 인터페이스에서 사용 했지만 실제로 인터페이스를 구현하려고 할 때 호환성 오류가 발생했습니다.

다음은 내가 겪은 문제에 대한 간단한 데모입니다.

interface iFoo
{
    public function bar (string $baz) : self;
}

class Foo implements iFoo
{

    public function bar (string $baz) : self
    {
        echo $baz . PHP_EOL;
        return $this;
    }
}

(new Foo ()) -> bar ("Fred") 
    -> bar ("Wilma") 
    -> bar ("Barney") 
    -> bar ("Betty");

예상 출력은 다음과 같습니다.

프레드 윌마 바니 베티

내가 실제로 얻는 것은 :

PHP 치명적 오류 : Foo :: bar (int $ baz) 선언 : Foo는 iFoo :: bar (int $ baz)와 호환되어야합니다 : 7 행의 test.php의 iFoo

문제는 Foo가 iFoo의 구현이므로 구현이 주어진 인터페이스와 완벽하게 호환되어야한다고 말할 수 있습니다. 아마도 인터페이스 나 구현 클래스 (또는 둘 다)를 변경하여 인터페이스를 사용하는 대신 이름으로 힌트를 반환하여이 문제를 해결할 수 self있지만, 내 이해는 의미 상 self"방금 메서드를 호출 한 클래스의 인스턴스를 반환" 을 의미 한다는 것입니다. ". 따라서 인터페이스로 변경하면 이론적으로 호출 된 인스턴스에 대한 의도가 반환 될 때 인터페이스를 구현하는 모든 인스턴스를 반환 할 수 있습니다.

이것은 PHP에 대한 감독입니까, 아니면 의도적 인 설계 결정입니까? 전자의 경우 PHP 7.1에서 수정 된 것을 볼 수 있습니까? 그렇지 않다면 인터페이스가 연결을 위해 방금 호출 한 인스턴스를 반환 할 것으로 예상하는 올바른 반환 방법은 무엇입니까?


self인스턴스를 참조하지 않고 현재 클래스를 참조합니다. 인터페이스가 동일한 인스턴스 를 반환해야 함 을 지정할 수있는 방법은 없습니다. self시도하는 방식으로 사용 하면 반환 된 인스턴스가 동일한 클래스 여야합니다.

즉, PHP의 반환 유형 선언은 불변이어야하지만 시도하는 것은 공변이어야합니다.

귀하의 사용 self은 다음과 동일합니다.

interface iFoo
{
    public function bar (string $baz) : iFoo;
}

class Foo implements iFoo
{

    public function bar (string $baz) : Foo  {...}
}

허용되지 않습니다.


반환 형식 선언 RFC는이 말을 :

상속 중 선언 된 반환 유형의 적용은 변하지 않습니다. 이는 하위 유형이 상위 메소드를 재정의 할 때 하위 유형이 상위와 정확히 일치해야하며 생략 할 수 없음을 의미합니다. 부모가 반환 유형을 선언하지 않으면 자식이 반환 유형을 선언 할 수 있습니다.

...

이 RFC는 원래 공변 반환 유형을 제안했지만 몇 가지 문제로 인해 불변으로 변경되었습니다. 미래의 어느 시점에서 공변 반환 유형을 추가 할 수 있습니다.


당분간 당신이 할 수있는 최선은 :

interface iFoo
{
    public function bar (string $baz) : iFoo;
}

class Foo implements iFoo
{

    public function bar (string $baz) : iFoo  {...}
}

또한 인터페이스에서 반환 유형을 명시 적으로 정의하지 않고 PHPDoc에서만 명시 적으로 정의한 다음 구현에서 특정 반환 유형을 정의 할 수있는 솔루션이 될 수 있습니다.

interface iFoo
{
    public function bar (string $baz);
}

class Foo implements iFoo
{
    public function bar (string $baz) : Foo  {...}
}

This looks like the expected behavior to me.

Just change your Foo::bar method to return iFoo instead of self and be done with it.

Explanation:

self as used in the interface means "an object of type iFoo."
self as used in the implementation means "an object of type Foo."

Therefore, the return types in the interface and the implementation are clearly not the same.

One of the comments mentions Java and whether you would have this issue. The answer is yes, you would have the same issue if Java allowed you to write code like that -- which it doesn't. Since Java requires you to use the name of the type instead of PHP's self shortcut, you are never going to actually see this. (See here for a discussion of a similar issue in Java.)


In case, when You want to force from interface, that method will return object, but type of object won't be the type of interface, but the class itself, then You can write it this way:

interface iFoo {
    public function bar (string $baz) : object;
}

class Foo implements iFoo {
    public function bar (string $baz) : self  {...}
}

It's working since PHP 7.4.

참고URL : https://stackoverflow.com/questions/39068983/php-7-interfaces-return-type-hinting-and-self

반응형