本文主要介绍“如何理解PHP7.2的父方法以及Liskov替换原理的相关问题”。在日常操作中,相信很多人对于如何理解PHP7.2的父方法以及Liskov替换原理的相关问题都有疑问。边肖查阅了各种资料,整理出简单易用的操作方法,希望能帮助大家解答“如何理解PHP7.2的母法以及Liskov替换原理的相关问题”的疑惑!接下来,请和边肖一起学习!
细说 PHP 7.2 子类覆盖方法省略参数类型功能以及 Liskov 替换原则
PHP 7.2已经问世一段时间了。只要你关心PHP的发展,你应该已经阅读了所有关于新版本的新改进。这只是一个可能被误解的新功能。
当子类覆盖父方法时,PHP 7.2可以忽略父方法的已定义参数的类型提示:
classFoo
{
public functionbar(someCLaSS $ obj){ }
}
classFoobarextendsFoo
{
Publicfunctionbar($obj){}//这是PHP7.2之前的错误。
}在看一些介绍这个功能的网站时,我说它的目的是“方便重新配置”。如果将来父方法的参数类型改变了,子类就不必再全部改变了”。听起来很合理。根据这种说法,它意味着如果子类忽略了父方法的参数类型,那么当调用它时,它仍然会检查参数类型。实际情况是否是这样,通过做一个实验就知道了:
?服务器端编程语言(Professional Hypertext Preprocessor的缩写)
classFoo
{
}
分类栏
{
publicfunctionsetFoo(Foo$foo)
{
}
}
classBarKidextendsBar
{
publicfunctionsetFoo($foo)
{
}
}
$ kid=newBarKid
$ kid-SetFoo(' Iamstring!');如果上面的语句是正确的,那么在接受字符串参数时,setFoo应该会报告一个错误。但是,上面的代码在7.2下没有任何错误信息,但是如果将参数类型添加到子类的setFoo方法中,它会立即报告错误。记得网上很多说法都不可信,除了我的小站.
上述实验表明子类方法可以省略参数类型,其目的当然不是为了方便重构。真正的目的是什么?
PHP 7.1中新增了一个函数,就是「可以设置方法或函数的参数和返回类型是否可以为空」。有一个规则看起来比较尴尬:“子类方法参数类型的范围比较宽松(即如果父类参数不能为null,子类参数可以支持null),但是返回类型比较紧(如果父类不能返回null,子类一定不能;如果父类可以返回null,子类就不能返回null)”,当时我只是简单的说了一句“娴Liskov替换原则”,但我没有深入介绍。我身边的PHPer不太关注OOP原理,但我觉得应该是每个工程师都知道的,下面就来介绍一下。
Liskov的替换原理很简单:在父类出现的地方,用子类替换也可以运行,即子类可以不假思索地替换父类。其实从语言设计的角度来说,我觉得这个原则是对自然规律的模仿。它不是简单的“模仿”。有兴趣的话可以看看新博客《企鹅不是鸟》。
比如人可以喝酒,可以喝茶,可以喝可乐,可以喝各种饮料,但是作为哺乳动物,人到底能不能喝水呢?另一方面,哺乳动物会喝水,但不一定会喝茶喝可乐,所以人是哺乳动物的一个子类。
从语言设计的角度来看,子类应该是父类的增强版,也就是应该能够处理比父类更多的对象类型,被覆盖的方法参数类型的扩展也体现了这个原则。
让我们谈谈返回类型,它可能有点迂回。子类为什么要缩小返回范围?事实上,很容易想到假设一个方法的返回将被用作另一个方法的参数。比如“水果饮料厂”这一类,有一种“生产”方式,就是把“果汁”退回来,传给“孩子”去“喝”。有一家橙汁厂,属于水果饮料厂的子类。其“制作”方法的返回式比较紧,只能返回“橙汁”,仍然给“孩子”喝,没有任何问题。
再举一个反例。如果有“水果饮料厂”的另一个子类,它的“生产”方法可以返回果酒和果汁,那么这个
子类很显然不能冒着给小朋友喝酒的风险去替换父类。
说完了 Liskov 替换原则,我们再来看看 7.2 里的这个改进,我们这时应该知道其实这也是 Liskov 原则的体现。目前来说,替换原则在 PHP 的实现并不完全。可能有人觉得这个版本是不是也支持『父类没有返回类型,子类可以有返回类型』呢?遗憾的是至少在 7.2 这个版本,并不支持,大家可以自行实验一下。
7.2 的另外一个新功能,是 object 可以作为任何对象的类型。见官方提供例子:
<?php function test(object $obj) : object { return new SplQueue(); } test(new StdClass());
其实在 7.2 发布之前,也是出于替换原则,有过一次关于『是否子类可以用 object 类型来替代被覆盖的方法对象参数的类型』,但最终投票并没有通过。虽然我不知道原因,但起码有人提了。
另外目前 PHP 不能像 Java 那样重载(overload),没有办法可以指定覆盖的方法的类型(目前只能把类型直接去掉,有点太粗暴):
<?php class Foo { } class FooFoo extends Foo { } class Bar { public function foo(FooFoo $foo) { } } class BarBar extends Bar { public function foo(Foo $foo) // 依然会报『子类不兼容父类方法格式』的错误 { } }
到此,关于“怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/96650.html