分析PHP7.2忽略父类方法以及Liskov替换原则相关问题

分析PHP7.2忽略父类方法以及Liskov替换原则相关问题

浏览次数:1280次
信息来源: 银河系资源网
更新日期: 2022-05-14
文章简介

细说 PHP 7.2 子类覆盖方法省略参数类型功能以及 Liskov 替换原则PHP 7.2 出来也有段时间了,关于新版本有什么新改进,只要你关心 PHP 的发展,应该都看过。这里只细说一个可能会有误解的新功能。PHP 7.2 可以在当子...

细说 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 版本之前是会报错的
}

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

<?php
class 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 这个版本,并不支持,大家可以自行实验一下。

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) // 依然会报『子类不兼容父类方法格式』的错误
    {
    }
}

但 PHP 也在不断的变化不是吗?最近 PHP 版本迭代这么快,我对 PHP 成为一个支持更多 OOP 特性的语言还是非常有信心的!

学习:《PHP7教程》

以上就是分析PHP7.2忽略父类方法以及Liskov替换原则问题的详细内容

标签: 暂无标签
php中变量是什么意思
« 上一篇
分析Kubernetes gRPC负载均衡(L4 vs L7 )
下一篇 »
  • php 怎么将json数据转成utf8
    45038阅读
    php将json数据转成utf8的方法:1、创建一个PHP示例文件;2、通过“json_encode($xm_json,JSON_UNESCAPED_UNICODE);”将json数组保存为utf8即可。本文操作环境:windows7系统、PHP7.1版、DELL G3电脑php 怎么将json数...
  • php安装 liunx参数有哪些
    6358阅读
    Linux安装PHP配置参数有:1、“--prefix”;2、“--with-config-file-path”;3、“--with-MySQL”;4、“--enable-safe-mode”;5、“--enable-zip”等等。本文操作环境:linux5.9.8系统、PHP7.1版、DELL G3电脑php...
  • php图片显示一片乱码怎么办
    2284阅读
    php图片显示一片乱码的解决办法:1、打开相应的PHP代码文件;2、在页面头部加上“header("Content-Type:image/jpg");”代码声明图片类型即可。本文操作环境:windows7系统、PHP7.1版、DELL G3电脑php图片显示一片乱码...
  • 如何解决php 长度不足问题
    2263阅读
    php长度不足的解决办法:1、创建一个PHP示例文件;2、通过“str_pad($value,2,0,STR_PAD_LEFT);”方式实现字符串固定长度不够补充其他字符串即可。本文操作环境:windows7系统、PHP7.1版、DELL G3电脑如何解决php 长...
  • php sql 字符串怎么转日期
    2086阅读
    php sql字符串转日期的方法:1、通过“date("Y-m-d",strtotime(""));”方式转换;2、通过“date("M-d-Y",mktime(0,0,0,$month,$day,$year));”方式转换。本文操作环境:windows7系统、PHP7.1版、DELL G3电脑php sql ...
  • 看看PHP有哪四种方法实现交换两个整型变量
    2082阅读
    看看PHP有哪四种方法实现交换两个整型变量?交换两个整型变量使用一个中间变量这种是最容易理解的$a = 1; $b = 2; $temp = $a; $a = $b; $b = $temp; var_dump($a, $b);不使用中间变量,就靠几次加减巧妙转换$a = 10...
  • php数组怎么求平均值
    1951阅读
    php数组求平均值的方法:1、用array_sum()计算数组中所有元素之和,语法“array_sum($arr)”;2、用count()获取数组中的元素个数,语法“count($arr)”;3、用“元素和/元素个数”语句计算出数组平均值。本教程操作环...
  • php 怎么判断错误次数
    1865阅读
    php判断错误次数的实现方法:1、实例化redis数据库;2、模拟数据库信息;3、接受用户输入信息;4、判断信息输入错误的次数即可。本文操作环境:Windows7系统、PHP7.1版、DELL G3电脑php 怎么判断错误次数?php 结合r...
  • php怎么实现点击删除代码
    1853阅读
    php实现点击删除代码的方法:1、创建一个PHP示例文件,并连接数据库;2、查询数据库;3、在超链接删除处调用javascript方法,并传递记录id即可。本文操作环境:windows7系统、PHP7.1版、DELL G3电脑php怎么实现点击删...
  • php 怎么把网页转换成图片格式
    1803阅读
    php把网页转换成图片格式的方法:1、装chrome-php/chrome;2、安装chromium;3、通过控制器实现转换逻辑即可。php 怎么把网页转换成图片格式?PHP将整个网页html转换为图片并保存【含滚屏】1、安装chrome-php/chrome...

如本文对您有帮助,随意赞赏一下!