Home  >  Article  >  Backend Development  >  Analysis of issues related to PHP7.2 ignoring parent class methods and Liskov substitution principle

Analysis of issues related to PHP7.2 ignoring parent class methods and Liskov substitution principle

藏色散人
藏色散人forward
2021-11-16 15:14:521453browse

Elaborate on PHP 7.2 subclass coverage method omitting parameter type function and Liskov substitution principle

PHP 7.2 has been out for a while, as long as you care about any new improvements in the new version You should have seen the development of PHP. Here I will only detail one new feature that may be misunderstood.

PHP 7.2 can ignore the parameter type (type hint) defined by the parent class method when the subclass overrides the parent class method:

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

I saw some website introductions When talking about this function, it is said that its purpose is to facilitate refactoring. If the parameter types of the parent class method change in the future, the subclass does not need to change them all." It sounds reasonable. According to this statement, the implicit meaning is: if the subclass ignores the parameter type of the parent class method, the parameter type will still be checked when it is called. You will know the actual situation by doing this experiment:

<?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;);

If the above statement is correct, setFoo should report an error when it accepts a string parameter. However, the above code does not report any error message under 7.2. But if the setFoo method of the subclass adds a parameter type, an error will be reported immediately. Remember that many opinions on the Internet are untrustworthy, except for my small website...

The above experiment shows that the subclass method can omit parameter types, and its purpose is definitely not to facilitate reconstruction. So what is the real purpose?

There is a new feature in PHP 7.1, which is "Whether the parameters and return type of a method or function can be set to null". There is a seemingly awkward rule: "The parameter type range of subclass methods is relaxed (that is, if the parent class parameter cannot be null, the subclass parameter can support null), but the return type is tightened (if the parent class cannot return null, the subclass parameter can support null) The class must not work; if the parent class can return null, the subclass does not need to return null)" I briefly said at the time that it was because of the "Liskov substitution principle", but did not introduce it in depth. Not many PHPers around me pay attention to OOP principles, but I think it should be known by every engineer, so I would like to introduce it.

Liskov's substitution principle is simple: wherever the parent class appears, it can be run if replaced by a subclass, that is, the subclass can replace the parent class without thinking. In fact, from the perspective of language design, I think this principle is the imitation of natural rules2018-09-29 Supplement: It is not a simple "imitation". If you are interested, you can read the new blog "Penguin is not bird".

For example, people can drink alcohol, tea, cola, and all kinds of drinks, but as mammals, humans can drink water no matter what, right? But conversely, mammals can drink water, but they may not be able to drink alcohol, tea or cola, so humans are a subcategory of mammals.

From the perspective of language design, the subclass should be an enhanced version of the parent class, that is, it should be able to handle more object types than the parent class, and the expansion of the overridden method parameter types is also the reason for this. The embodiment of a principle.

Let’s talk about the return type, which may be a bit convoluted. Why should subclasses narrow the return range? In fact, as long as you assume that the return of one method will be used as a parameter of another method, it is easy to think about. For example, a "Fruit Beverage Factory" class has a "Production" method that returns "Fruit Juice" and passes it to the "Kid"'s "Drink" method. There is an "Orange Juice Factory" class that is a subclass of "Fruit Beverage Factory". The return type of its "Production" method is narrowed and can only return "Orange Juice". It is still given to "children" to "drink" and will not appear. any problem.

Give another counterexample. If another subclass of "Fruit Beverage Factory" appears, and its "Production" method can return fruit wine in addition to fruit juice, then this subclass obviously cannot replace the parent class at the risk of drinking for children.

After talking about Liskov’s replacement principle, let’s take a look at this improvement in 7.2. We should know at this time that this is actually a manifestation of Liskov’s principle. Currently, the implementation of the substitution principle in PHP is incomplete. Some people may think that this version also supports "the parent class has no return type, and the subclass can have a return type"? Unfortunately, at least in version 7.2, it is not supported. You can experiment by yourself.

Another new feature of 7.2 is that object can be used as the type of any object. See the official example:

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

In fact, before the release of 7.2, also based on the substitution principle, there was a question about "whether subclasses can use object types to replace the types of overridden method object parameters", but in the end The vote did not pass. Although I don't know the reason, at least someone mentioned it.

In addition, currently PHP cannot overload like Java, and there is no way to specify the type of the overridden method (currently the type can only be removed directly, which is a bit too crude):

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

But PHP is constantly changing, right? The PHP version has been iterating so fast recently, and I am very confident that PHP will become a language that supports more OOP features!

Recommended study: "PHP7 Tutorial"

The above is the detailed content of Analysis of issues related to PHP7.2 ignoring parent class methods and Liskov substitution principle. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:chrisyue.com. If there is any infringement, please contact admin@php.cn delete