文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题

2023-06-25 15:40

关注

这篇文章主要介绍“怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题”,在日常操作中,相信很多人在怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

细说 PHP 7.2 子类覆盖方法省略参数类型功能以及 Liskov 替换原则

PHP 7.2 出来也有段时间了,关于新版本有什么新改进,只要你关心 PHP 的发展,应该都看过。这里只细说一个可能会有误解的新功能。

PHP 7.2 可以在当子类覆盖(override)父类方法的时候,忽略父类方法的定义的参数的类型(type hint):

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

我看有些网站介绍此功能的时候,说其目的是为了『方便重构。如果以后父类方法的参数类型变了,子类不用再全部换一遍』。听起来好像很有道理。按这说法,隐含的意思是:如果子类忽略了父类方法参数类型,被调用时还是会检查参数类型。实际情况是不是这样做一下实验就知道了:

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

如果上面的说法是对的,setFoo 接受字符串参数的时候就应该报错,然而上面代码在 7.2 下并没有任何报错信息,但如果子类的 setFoo 方法加上了参数类型,就会立马报错了。记住网上很多说法都不可信,除了我这个小站……

上面的实验说明子类方法可省略参数类型,其目的肯定不是为了方便重构。那真正目的是什么呢?

在 PHP 7.1 里有一个新功能,是『可设置方法或函数的参数和返回类型是否可以为 null』。其中有一条看上去比较别扭的规则:『子类方法参数类型范围放宽(即父类参数若不能为 null ,子类参数可支持 null),但返回类型缩紧(父类若不能返回 null,子类必须也不行;若父类可以返回 null,子类可以不返回 null)』,当时我很简单说了一句,是因为 『Liskov 替换原则』,但没有做深入介绍。身边的 PHPer 们关注 OOP 原则的不多,但我认为它应该被每个工程师知道,还是介绍一下。

Liskov 替换原则简单一句话:父类出现的地方,替换成子类也能运行,即子类可无脑替换父类。其实从语言设计来说,我认为此原则就是对自然规则的模仿2018-09-29 补充:也不是简单的『模仿』,有兴趣可阅读新博客『企鹅不是鸟』。

举个例子,人可以喝酒,喝茶,喝可乐,喝各种饮料,但人作为哺乳动物,怎么着都能喝水吧?但反过来,哺乳动物能喝水,但不一定能喝酒喝茶喝可乐,所以人是哺乳动物的子类。

从语言设计的角度来说,子类就应该是父类的加强版,就是要能比父类处理更多的对象类型,而被覆写的方法参数类型的扩大,也是这一原则的体现。

再来说可能有点绕的返回类型,为什么子类要缩小返回的范围呢?其实只要假设一个方法的返回会作为另外一个方法的参数,就很好想了。比如一个『水果饮料厂』类,有一个『生产』方法,返回『水果汁』,并传给了『小朋友』的『喝』方法。有一个『橘子汁工厂』类属于『水果饮料厂』的子类,它的『生产』方法返回类型缩紧,只能返回『橘子汁』,依然给『小朋友』『喝』,并不会出现任何问题。

再举一个反例。如果又出现一个『水果饮料厂』的子类,其『生产』方法除了返回水果汁,还能返回果酿酒,那这个子类很显然不能冒着给小朋友喝酒的风险去替换父类。

说完了 Liskov 替换原则,我们再来看看 7.2 里的这个改进,我们这时应该知道其实这也是 Liskov 原则的体现。目前来说,替换原则在 PHP 的实现并不完全。可能有人觉得这个版本是不是也支持『父类没有返回类型,子类可以有返回类型』呢?遗憾的是至少在 7.2 这个版本,并不支持,大家可以自行实验一下。

2 的另外一个新功能,是 object 可以作为任何对象的类型。见官方提供例子:

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

其实在 7.2 发布之前,也是出于替换原则,有过一次关于『是否子类可以用 object 类型来替代被覆盖的方法对象参数的类型』,但最终投票并没有通过。虽然我不知道原因,但起码有人提了。

另外目前 PHP 不能像 Java 那样重载(overload),没有办法可以指定覆盖的方法的类型(目前只能把类型直接去掉,有点太粗暴):

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

到此,关于“怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯