• 【辅导】Task12 使用类和对象 主要知识点(2)


    这次辅导主要是对类的多态性进行讲解。由于PHP是弱类型语言,所以导致在有些特征上有与Java等语言不同的地方,但总体上是差不多的。

    1、实现类多态的三种途径

    类的多态,就是用基类(父类)去管理派生类(子类),这些父类与派生类具有一致的行为,当父类对象指向子类对象的时候,具有的是子类的行为。

    可以通过以下三种方式实现类的多态:

    (1)重写父类方法

    (2)使用抽象类

    (3)实现接口

    2、重写父类方法

    从父类继承,你会得到父类的所有属性和方法,只不过受保护级别限制,public成员,你可以使用,别人也可以访问;protected成员,你自己和自己的子类可以访问,别人不能访问;private成员,你看不到,也使用不了(这一点有分歧,有人认为私有属性和方法不继承)。

    在子类中,重新定义一个与父类同名的方法,称为方法重写。

    方法重写时的注意事项:

    (1)方法名与参数个数必须相同。参数不一致,会有warning提示。这一点与Java稍有不同。

    (2)重写的方法的保护级别必须小于等于父类的方法。父类方法是public的,重写方法可以public、protected、private都可以;父类方法是protected,重写方法可以是protected和private。父类方法是private的,那子类可以定义一个新方法(这个方法正好与父类方法同名)。

    (3)如果类的方法被声明为final,那这个方法不能被重写。如果类被声明为final,那这个类不能被继承了。

    子类调用父类成员使用范围运算符:parent::成员名,前提是保护级别允许(public或protected)。

    3、这真的是多态吗?

     

    上面的foreach循环中,$shape是什么类型的变量? 在循环中加个调试语句试一下:

    var_dump($shape);

    会发现$shape变量分别是Point、Circle、Rectangle、Cylinder和Cube类型对象。主要是因为PHP是弱类型,它是通过赋值的数据推断类型的。

    这意味着,如果不使用继承来完成这些类,只要保证这些类都有同样的getArea()和getVolume()方法,也可以实现这个功能。Java这类强类型不行,因为每个变量要有明确的类型,所以只能通过基类去管理派生类。

    但你如何保证呢?从另一种形式说,通过继承和方法重写(即多态),你可以保证一组类具有相同的行为,从这一点说,这也是多态。

    4、instanceof运算符

    instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例。

    子类属于父类的实例,所以如果 $c是Circle类对象,$c instacneof Point的结果是true。

    instanceof也可以用来判断类对象是否实现了某个接口。

    6、抽象类

    抽象类用abstract定义。类中只要有一个方法是抽象方法,这个类就必须定义为抽象的。如果全是实体方法,这个类也可以定义为抽象类。

    抽象类只能由子类来继承,不能用来实例化对象。因为不能实例化,所以没有构造函数与析构函数。

    子类从抽象类继承,必须实现(重写)所有抽象方法。其它实体方法可以重写也可以不重写,没有重写就继承过来。

    子类实现了抽象方法就是实体方法了,它的子类可以继承过来,可以重写也可以不重写。

    使用抽象类,主要是因为有些方法不好定义具体的行为,就交给子类来定义的,同时也保证子类具有一致的行为。

    方法重写规则与前面一致。

    7、接口

    接口使用interface定义。同类一样,不定义访问属性,都是public。

    接口名称建议是i开头,如iCountable。

    接口中可以定义方法和常量,都必须是public的。

    接口中定义的所有方法都是空方法(只是说明没有实现)。

    接口中可以定义构造函数。(工厂模式时有用,与Java不同)

    一个类要实现接口,使用implements关键字。一个类只能从一个父类继承,但可以实现多个接口。

    实现接口的类,必须实现接口中所有方法(不然会有致命错误Fatal error),并且实现时,方法的定义形式要与接口中的定义一致(方法名与参数名称均要完全相同)。

    接口也可继承自一个或多个接口,使用extends关键字。

    PHP没有完全解决好接口中的名称冲突问题。如果一个类实现多个接口,这些接口中可以有同名的方法,但这些方法的定义必须签名相同。

    接口中可以定义常量。常量使用方法与类的常量相同,后面讲。

    8、类的静态成员

    类中可以定义静态字段和静态方法,使用static关键字。

    在类的内部,使用self关键字来引用,如:self::$count

    在类的外部,使用类名来引用,如:Student::getCount()

    9、理解浅复制

     

    将一个类的对象(已经用new 实例化)赋值给一个变量,得到的是这个对象的引用(两个变量指向同一个对象),不管有没有用&运算符。

    使用clone运算符,可以将对象复制一份给变量(可以说是2个对象了)。但是如果这个对象里面的有字段是其它类的对象(比如学生对象里面有课程字段,它是Course类的对象),这些字段克隆过去仍然是引用(浅复制)。除非你去定义__Clone魔术函数(自己决定这些字段如何复制过去)。

    10、类的常量

    可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用 $ 符号。使用const关键字来定义(不是使用define函数)。

     

    在类的内部,使用self关键字来引用,如:self::constant

    在类的外部,使用类名来引用,如:MyClass::constant

    11、trait简介

    trait是PHP提供的一种代码复用的方法,他主要用于类的组合(接口也是组合的一种方式,但接口中只有抽象方法)。

    trait的定义与class一样,除了关键字是使用trait而不是class。

    trait不能用来实例化对象,只能在定义类时,通过use语句引用到类中。(个人感觉没什么用,仅仅是方便程序员复用代码)。

    可以这么理解,继承是纵向组合代码,trait是横向组合代码。

    12、类型约束:方法的参数可以指定类型

    看下面的例子:

     

    为函数ShowArea指定了参数必须为Point类型,那么,Point类的子类都可以作为参数传递给它,结果是:

     

    但Student类对象不能传递给它,会有错误:

     

     

    类类型、接口、数组、Callable(函数)可以作为类型约束,但标量类型(如int,string)不能作为类型约束(因为能自动进行类型转换)。

    类中的方法也支持类型约束。

    13、练习一下

    将我们在Java中学习的,使用抽象类和接口方式实现的多态性演示,在PHP中实现一下。

  • 相关阅读:
    vue 组件之间的通讯方式
    vue 路由4种传参方式
    vue+axios封装已文件流的形式导出文件
    vue 开发环境正常打包之后背景图片无法访问或者element-ui的icon找不到
    vue 优化webpack引入CND
    microtime() — 返回当前 Unix 时间戳和微秒数
    将一个字符串分隔为组成它的字符
    Laravel 伪静态配置
    VSCode
    array_merge()&array_combine()合并数组函数
  • 原文地址:https://www.cnblogs.com/whitewin/p/12658394.html
Copyright © 2020-2023  润新知