>  기사  >  백엔드 개발  >  상위 클래스 메서드와 Liskov 대체 원칙을 무시하는 PHP7.2 관련 문제 분석

상위 클래스 메서드와 Liskov 대체 원칙을 무시하는 PHP7.2 관련 문제 분석

藏色散人
藏色散人앞으로
2021-11-16 15:14:521351검색

매개변수 유형 함수를 생략한 PHP 7.2 하위 클래스 적용 방법 및 Liskov 대체 원리에 대해 자세히 설명합니다.

PHP 7.2가 출시된 지 꽤 됐습니다. 새 버전. 여기서는 오해할 수 있는 새로운 기능 하나만 자세히 설명하겠습니다.

PHP 7.2에서는 하위 클래스가 상위 클래스 메소드를 재정의할 때 상위 클래스 메소드에서 정의한 매개변수 유형(유형 힌트)을 무시할 수 있습니다.

class Foo
{
    public function bar(SomeClass $obj) {}
}
class Foobar extends Foo
{
    public function bar($obj) {} // 这在 PHP7.2 版本之前是会报错的
}

일부 웹사이트에서 이 기능을 도입할 때 그 목적을 언급한 것을 봤습니다. 나중에 상위 클래스 메소드의 매개변수 유형이 변경되더라도 하위 클래스는 이를 모두 변경할 필요가 없습니다." 합리적인 것 같습니다. 이 설명에 따르면 암시적인 의미는 다음과 같습니다. 하위 클래스가 상위 클래스 메서드의 매개 변수 유형을 무시하면 호출 시 매개 변수 유형이 계속 확인됩니다. 다음 실험을 수행하여 실제 상황인지 확인할 수 있습니다.

<?php
class Foo
{
}
class Bar
{
    public function setFoo(Foo $foo)
    {
    }
}
class BarKid extends Bar
{
    public function setFoo($foo)
    {
    }
}
$kid = new BarKid;
$kid->setFoo(&#39;I am a string!&#39;);

위 명령문이 정확하다면 setFoo는 문자열 매개변수를 허용할 때 오류를 보고해야 합니다. 그러나 위 코드는 7.2에서는 오류 메시지를 보고하지 않습니다. 하지만 하위 클래스에서 setFoo 메소드가 매개변수 유형을 추가하면 오류가 즉시 보고됩니다. 내 작은 웹사이트를 제외하면 인터넷의 많은 진술은 신뢰할 수 없다는 점을 기억하십시오...

위 실험은 하위 클래스 메서드가 매개 변수 유형을 생략할 수 있으며 그 목적은 확실히 리팩토링을 용이하게 하는 것이 아니라는 것을 보여줍니다. 그렇다면 진짜 목적은 무엇인가?

PHP 7.1에는 "메서드나 함수의 매개변수와 반환 유형이 null이 될 수 있는지 여부를 설정할 수 있습니다"라는 새로운 기능이 있습니다. 겉으로는 어색해 보이는 규칙이 있습니다. "하위 클래스 메서드의 매개 변수 유형 범위는 완화되지만(즉, 상위 클래스 매개 변수가 null이 될 수 없는 경우 하위 클래스 매개 변수는 null을 지원할 수 있음) 반환 유형은 엄격해집니다(상위 클래스의 경우 null을 반환할 수 없으면 하위 클래스 매개 변수는 null을 지원할 수 있습니다.) 상위 클래스가 null을 반환할 수 있으면 하위 클래스는 null을 반환할 필요가 없습니다. 대체원리'에 대해 설명하고 있으나 심도 있게 소개하지는 않았다. 내 주변에 OOP 원리에 관심을 갖는 PHPer는 많지 않지만, 엔지니어라면 누구나 알아야 한다고 생각해서 소개하고 싶다.

Liskov의 대체 원칙은 간단합니다. 상위 클래스가 나타나는 곳마다 하위 클래스로 대체되면 실행할 수 있습니다. 즉, 하위 클래스는 생각 없이 상위 클래스를 대체할 수 있습니다. 사실 언어 디자인의 관점에서 보면 이 원리는 자연 법칙의 모방이라고 생각합니다2018-09-29 보충: 단순한 '모방'이 아닌 관심이 있으신 분은 새 블로그를 읽어보시면 됩니다. "펭귄은 새가 아니다".

예를 들어 사람은 술, 차, 콜라 등 온갖 음료를 마실 수 있지만 포유류인 인간은 물은 어떻게 해서든 마실 수 있잖아요? 하지만 반대로 포유류는 물을 마실 수 있지만 반드시 술이나 차, 콜라를 마실 수는 없을 수도 있으므로 인간은 포유류의 하위 범주에 속합니다.

언어 디자인의 관점에서 하위 클래스는 상위 클래스의 향상된 버전이어야 합니다. 즉, 재정의된 메서드 매개 변수 유형의 확장은 상위 클래스보다 더 많은 객체 유형을 처리할 수 있어야 함을 의미합니다. 이 원칙.

조금 복잡할 수 있는 반환 유형에 대해 이야기해 보겠습니다. 하위 클래스가 반환 범위를 좁혀야 하는 이유는 무엇입니까? 사실, 한 메서드의 반환이 다른 메서드의 매개변수로 사용될 것이라고 가정하는 한, 생각하기 쉽습니다. 예를 들어, "Fruit Beverage Factory" 클래스에는 "Fruit Juice"를 반환하고 이를 "Kid"의 "Drink" 메서드에 전달하는 "Production" 메서드가 있습니다. "Fruit Beverage Factory"의 하위 클래스인 "Orange Juice Factory" 클래스가 있습니다. 해당 "Production" 메서드의 반환 유형이 좁아지고 "Orange Juice"만 반환할 수 있습니다. 음료"라고 표시되며 나타나지 않습니다. 질문이 있습니다.

또 다른 반례를 들어보세요. "과일 음료 공장"의 또 다른 하위 클래스가 나타나고 해당 "생산" 메서드가 과일 주스 외에 과일주를 반환할 수 있는 경우 이 하위 클래스는 어린이가 마실 위험이 있는 상위 클래스를 대체할 수 없습니다.

리스코프의 대체 원리에 대해 이야기한 후, 7.2의 개선 사항을 살펴보겠습니다. 이때 실제로 이것이 리스코프의 원리를 구현한 것임을 알아야 합니다. 현재 PHP의 대체 원칙 구현은 불완전합니다. 어떤 사람들은 이 버전이 "상위 클래스에는 반환 유형이 없고 하위 클래스에는 반환 유형이 있을 수 있습니다"도 지원한다고 생각할 수 있습니다. 안타깝게도 적어도 버전 7.2에서는 직접 실험해 볼 수 없습니다.

7.2의 또 다른 새로운 기능은 객체를 모든 객체의 유형으로 사용할 수 있다는 것입니다. 공식 예를 참조하세요:

<?php
function test(object $obj) : object
{
    return new SplQueue();
}
test(new StdClass());

사실 7.2 릴리스 이전에도 대체 원칙에 따라 "서브클래스가 재정의된 메소드 객체 매개변수의 유형을 대체하기 위해 객체 유형을 사용할 수 있는지 여부"에 대한 질문이 있었지만 최종 투표가 통과되지 않았습니다. 이유는 모르겠지만 적어도 누군가는 언급했습니다.

또한 현재 PHP는 Java처럼 오버로드할 수 없으며 재정의된 메서드의 유형을 지정할 방법이 없습니다(현재 유형은 직접 제거할 수만 있는데 이는 다소 거칠습니다).

<?php
class Foo
{
}
class FooFoo extends Foo
{
}
class Bar
{
    public function foo(FooFoo $foo)
    {
    }
}
class BarBar extends Bar
{
    public function foo(Foo $foo) // 依然会报『子类不兼容父类方法格式』的错误
    {
    }
}

하지만 PHP는 지속적으로 바뀌는 거 맞지? 최근 PHP 버전이 매우 빠르게 반복되고 있으며, PHP가 더 많은 OOP 기능을 지원하는 언어가 될 것이라고 확신합니다!

추천 학습: "PHP7 Tutorial"

위 내용은 상위 클래스 메서드와 Liskov 대체 원칙을 무시하는 PHP7.2 관련 문제 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 chrisyue.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제