PHP 继承——有限继承|学习笔记

简介: 快速学习 PHP 继承——有限继承

开发者学堂课程【PHP 进阶教程-由浅入深掌握面向对象开发-第二阶段继承相关概念和实现】学习笔记,与课程紧密联系,让用户快速学习知识。  

课程地址:https://developer.aliyun.com/learning/course/712/detail/12692


PHP 继承——有限继承

 

内容介绍:

一、目标

二、概念

三、示例

四、小结

 

前面的课讲了继承语法,发现继承之后,子类对象可以访问父类的成员,问题是哪些能够访问?哪些用来被继承?有没有不可被继承的?所以本节,通过有限继承来学习解决这些问题。

 

一、目标

本节目标:理解 PHP 中继承的内容(继承哪些东西),并且掌握架构中的设计方案,去实现真正的应用继承。

 

二、概念

1.有限继承:指子类在继承父类成员的时候,并非继承所有内容,而是继承并使用父类部分内容(只能使用其一个部分的内容)。

(1)PHP 中继承的本质是对象继承。(对象去访问的是属性和方法,所以继承通常是指对象继承。)

(2)PHP 中继承的内容:父类所有公有成员(属性和方法,都可以继承)受保护成员和私有属性都可以继承,唯独私有方法不能继承。这点需要明确。

(3)受保护(protected:关键字,访问修饰限定符号)成员是专门用于实现继承的,专门为继承而生,可以在父类或者子类的内部访问(相关类的内部),这时就体现出了相关性:“子类和父类都可以访问。”这叫做相关类,但前提是要实现继承,当然不继承也无法体现叫父类或者子类。

(4)私有成员的访问,虽然属性被继承,但是只能在所属类(因为私有成员只能在自己的类里进行访问)中设定公有或者受保护的方法来实现访问。不然子类里面也访问不了私有属性,因为私有的特性是只能在自己类里面的方法进行访问。

(5)为了使结构的完整性得到保留,静态成员也遵循继承规则:因为静态成员所属于类,从结构的角度分析,类继承类,所以也可以享受这种待遇,即子类可以访问父类静态成员。(前提是满足继承条件,就可以实现访问)

这是所谓有效继承的概念,指继承所有的部分,只有私有方法不能被继承,其他的都可以被继承。

 

三、示例

有了这种继承方式,接下来看具体的实现

1. 继承内容:PHP 中继承是子类继承父类所有的公有成员、受保护成员和私有属性,不能继承父类是的私有方法。

该如何验证此操作以及如何验证确实继承了这些内容?可以通过一个代码来实现。在此父类里面常量,公有属性,受保护属性和私有属性全部都有。这是各类方法,方法里面分别访问的是对应属性,私有方法访问的是私有属性,然后子类去继承父类。

#父类

class Human{

const CALL =‘人’;

public $name =‘human’;

protected $age =‘100’;

private $money =‘100’;

public function showName(){

echo $this->name ;

}

protected function showAge(){

echo $this->age;

}

private function showMoney(){

echo $this->money;

}

}

#子类

class Man extends Human{}

#实例化子类

$m = new Man() ;

var_ dump($m) ;         #可以看到父类私有属性:说明被继承

$m-> showName() ;       #允许直接访问:方法为公有允许类外访问

关键观察对象里有什么能帮助此处得到继承,新建02extens.php 这样的一个有限继承,因为此类代码较多,但本身比较简单,故将其复制过来。

image.png

同时具有父类、常量、属性、方法。属性以及方法都有范围修饰限定符限定,公有以及私有都具有。然后子类继承父类继承,输入 class Man extends Human{}这样就完成了继承。完成继承之后,接下来输入空类(因为没进行其他操作)。

image.png

然后进行实例化(子类),实例化父类与子类没有关系,输入$m = new Man() ;var_ dump($m) ;

image.png

然后可以观察对象到底属于什么类型。因为如果其私有属性可以继承,那本身的对象(Man)对象没有属性,除非其私有在这里存在,才可以证明真的继承成功了。

访问02extens.php,发现里面确实拥有三个属性。不管是 man 这样类的对象、公有的 name 属性,还是受保护的 age 属性,又或者是 private 的 human 类的 money 属性全部都有。说明属性都被继承了,那属性继承了,当然要确定所谓的 showmoney 能否访问私有方法,私有的 showname 和公有的肯定可以进行访问。showage 受保护的,私有的则是不一定能访问。那么先进行属性证明,先证明父类属性(父类本质输入的是父类对象)确实被子类继承了。

接下来看方法的调用,调用 showname,输入“$m->showname();”这是公有方法,点击刷新,结果显示成功。再输入“$m->showage();”点击刷新,结果显示错误,错误的原因是访问了一个受保护的方法,但是环境不对。

image.png

出现这种错误的原因是受保护的只能在类的内部访问,但是是相关类。

2. 受保护继承 protected,protected 的关键字的产生本身就是纯用于继承的,表示允许被子类在子类内部访问的意思,而不允许被外部直接访问。

其只能证明,在类的内部访问。如果需要在外部访问,则不能证明其可以被继承或者使用。所以需要在子类里面增加一个方法来访问父类受保护的内容,包括属性和方法。

#父类

class Human{

protected $age =‘100’;

protected function showage(){

echo Sthis->age;

}

}

#子类

class Man extends Human{

#在子类内部增加公有访问访问继承自父类的受保护成员

public function getprotected( ){

echo sthis->age;      #访问父类受保护属性

$this-> showAge();    #访问父类受保护方法

}

}

#实例化子类对象

$m = new Man();

$m->getProtected();            #正确输出:说明可以访问

子类通常是有内容的,在子类的{}中输入“Public function getprotected(){”。

image.png

第一步,输入# 访问继承的受保护内容,然后输入 echo $this->age(受保护的有 age),然后再调用父类的方法 Showage,也就是输入$this-> showAge();这时候看这个情况到底能否成功,在外部需要让此方法触发,shouage 既然不能访问,那这里就访问自己的方法(getprotected),因为这是公有的,所有一定可以访问。点击刷新发现,不管是访问 showage,还是直接访问 age 都输出了100,这也说明说明受保护的内容不管方法还是其他,确实可以被继承。

image.png

接下来需要证明私有。私有按照这种方式,输入“Public function getprivate”,然后输入 echo $this->money,很明显这里明显不能进行访问。接着输入$this->showMoney();

image.png

让此方法运行一下,下方新建一行 getPrivate(),点击刷新发现结果错误,错误原因第一个是 Man 里没有叫做$money 的属性,它并没有显示不能访问,其只是告诉当前 Man 类里没有叫做$money 的属性。这里是继承了,但是继承对应的 money 属性,但是 money 是私有的。私有的其前面是带着类名的(Human),所以其实这里确实没有属于当前 man 类能访问的 money 属性。

那此方法很明显也是没有访问的,私有的方法不允许进行访问。说明私有的方法,无法实现访问父类的内容的任务。还有一点是属性也无法访问,虽然可以继承,但不代表一定可以访问。所以这个地方可以证明:被继承,但是无法在子类中访问,这是私有的特性。虽然下面也无法证明没有被继承,但是一定是不能访问的。实际确实没有被继承,这就是上文的私有的内容。

image.png

3. 访问父类私有成员:子类若想访问父类私有成员,那么前提是父类提供了能够访问私有成员的接口:即提供了公有或者受保护的方法给子类访问。

私有成员,如果想要去访问父类的私有成员,前提就是除非父类开放接口允许访问。不管使用了受保护还是 public,其开放了接口才能去访问,如果没有开放则不能访问。如果父类允许私有给你访问的情况,其通常会进行一个受保护,因为其不允许外部访问,但是允许子类访问(受保护专为子类提供)。

#父类

class Human{

private $age = 100;

private $money. = 100;

#提供接口供子类访问:此时通常是受保护的方法,肯定不允许外部直接访问的

#protected function getAge(){

echo $this->age ;

}

}

#子类

class Man extends Human{

#依然需要定义方法来访问继承自父类的受保护的成员

public function showprivate(){

$this->getAge();

}

}

# 实例化子类对象

$m = new Man() ;

$m-> showprivate();         #输出100,表示正确访问

所以如果确实要进行这样的操作,可以这样进行:输入 protected function getmoney(){ ,然后输入 echo $this->money。上面是可以进行访问的,因为上面在父类里。在下面需要调用时,这两个错误的不能调用,但如果非要用父类的公共接口是没有问题的。父类私有属性,除非父类提供能继承的方法访问,不然无法进行访问。这时的方法是输入$this->getMoney();这个结果的值100是可以数出来的,而且不会报错,以上介绍了继承内容,包括继承之后怎么去使用,protected 关键字是用来修饰什么样的内容,修饰之后的效果都在这里体现。

image.png

注意:虽然子类可以通过以上方式来实现访问父类的私有成员(包括私有方法),但是从设计的意义上讲,私有就是不允许外部访问,所以父类通常不会提供对外的访问接口,以上案例只是为了知识说明。虽然能够允许通过以上方式修改父类去实现目标,但正常情况从设计的意义来讲,做私有的目的就是为了不允许外部访问,只能在内部访问,所以也没有必要为子类对象去开放私有的访问。如果可以外部访问就直接设计成 protected 这样的特性,所以上述情况,基本上用的也并不是很多。

4. 静态成员(类常量)也遵循继承规则(PHP 继承本质是对象),只是访问方式是由类进行访问。

上面都是以对象为例子来讲的,里面没有涉及到类的访问,但是本质上来讲,静态的成员也是遵循继承的规则,只是访问方式不再是由对象来访问,而是由类来访问。

例如 Man、$count,首先访问子类,子类没有的情况下找父类,父类拥有就可以访问,方法同样也可以访问。如果有受保护的静态方法想要被访问,使用在子类里面增加公共方法以及共有的方法去将其调用,这里使用类名去进行一些相应的访问,因为这是对应的范围解析操作符来操作,是类成员来访问。可以自行去运行一遍这个代码,因为本质与对象的继承实现是一样的。

class Human{

const NAME =‘人’ ;

public static $count=0;

protected static $type = array(‘黑’,‘白’,‘黄’);

public static function getcount(){

echo self: :NAME;

echo self: :$count;

}

protected static function getType(){

Print_r(self::$type);

}

}

class Man extends Humanf

#依然需要子类中访问受保护成员

pub1ic static function getHuman(){

Human: :getType();

}

}

echo Man: :Scount;          #允许直接访问

Man: :getcount() ;          #访问父类静态方法

Man: :getHuman() ;          #利用子类公有方法访问父类受保护成员

5.构造方法和折构方法也可以被子类继承,此时需要注意子类对象实例化时对应的父亲扩造方法的参数

#父类

class Human

private $money;

public function _construct($money){

$this->money = $money;

}

public function _destruct(){

echo ‘die';

}

}

#子类继承

class Man extends Human{}

#子类实例化:自身是空类,没有指定构造方法

#$m = new Man() ;        #错误:缺少参数,因为会自动调用父类构造方法

$m = new Man(100);     #正确

会被子类继承这点要特别注意,因为有时父类有构造方法,然后发现子类也需要构造方法,或者发现子类就没有,去实例化时忽略了要去提供数据等。例如在上面有 money,但是给其增加一个构造方法,以构造方法为例,因为析构方法本身用的不多。这里增加了一个要属性的父类构造方法,然后此时这段代码本来正常运行,但是现在一运行就会报错。就是因为此类虽然自己本身没有构造方法,但是继承了父类构造方法,它需要一个参数,所以在 man()必须要给它传个值,例如五块钱。

image.png

传之后这段代码又可以运行,所以这是构造方法特性,构造方法通常都是公有,所以都会被继承。此时如果涉及到还有要继承的情况,注意父类如果私有化构造方法,那么子类是否会受到影响呢?输入Private 观察,对比一下发现子类依然显示是错误,说明了私有的方法确实是不能访问。这里其实也能说明,父类的私有方法其实本质也是被继承的,只是不能用而已,所以继承就可以理解为继大承,即所有东西都被继承。所以这种方法要做的特殊一点,构造方法要特殊。并且要注意,因为此是无法控制的,其一定会被调用,析构方法也一致,出现这种情况也会被调用。只是析构并不重要,所以一般不存在问题。

 

四、小结

1、继承是有限继承,理论上是用来继承父类允许被继承的部分,实际上都可以继承,只是继承完无法使用,即使用 public 或者protected 修饰的成员 (有限继承指的是有限能用而已)。

例如私有的属性和方法可以继承,但无法使用。

2、因为对象的属性是保存在对象内存空间,所以父类的私有属性也会继承。

继承的本质就是把两个类里所有的东西都拿过来,这才有了前面打印子类对象时发现父类所以属性都在其中。

3、父类私有成员本质不允许被子类访问,但是可以通过父类开放接口实现(一般不会这么操作)

4、静态成员也可以遵循继承规则。

可以独自运行上文提供的代码,去理解怎么实现继承,继承之后不再用对象而是用类访问。

5.构造方法也可以被继承,因此在实例化子类对象的时候,要考虑到父类构造方法所使用到的参数问题。

在实例化当中,在父类里面没有特殊情况,一般不会让父类使用构造方法,或者除非子类不用构造方法,一般就会使用父类的统一构造方法,父类有构造方法的前提下,在实例化子类对象的时候要考虑传参的问题,保证父类的对象可以真正的被实例化从而被子类继承。

相关文章
|
12月前
|
存储 Java 数据库连接
php学习笔记-代码基本语法-day01
本文是关于PHP编程语言的基础语法学习笔记,内容包括PHP的介绍、注释风格、数据类型、命名规范、常量和变量的使用,以及变量和常量相关的常用函数。文中详细解释了PHP的基本语法元素和一些易混淆的概念,如传值赋值与传址赋值、可变变量,以及如何检查变量是否已定义或为空。
php学习笔记-代码基本语法-day01
|
12月前
|
JavaScript 前端开发 安全
php学习笔记-普通表单参数提交获取及页面的重定向和一个登录小demo-day05
本文介绍了PHP中普通表单参数的提交获取、页面重定向的方法,并通过一个登录示例演示了表单参数的封装和页面跳转处理。
|
12月前
|
存储 缓存 数据处理
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
本文介绍了PHP会话控制及Web常用的预定义变量,包括`$_REQUEST`、`$_SERVER`、`$_COOKIE`和`$_SESSION`的用法和示例。涵盖了cookie的创建、使用、删除以及session的工作原理和使用,并通过图书上传的例子演示了session在实际应用中的使用。
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
|
12月前
|
Java PHP 数据安全/隐私保护
PHP 面向对象,构造函数,析构函数,继承,方法的重写,接口抽象类,static,final,this,parent,self的异同和作用
本文详细介绍了PHP面向对象编程的一系列核心概念和用法,包括构造函数、析构函数、继承、方法重写、访问控制、接口、抽象类、静态成员、final关键字、以及this、self、parent这三个关键字的异同和作用。通过具体示例代码,展示了如何在PHP中使用这些面向对象的特性,以及它们在实际开发中的应用。
PHP 面向对象,构造函数,析构函数,继承,方法的重写,接口抽象类,static,final,this,parent,self的异同和作用
|
12月前
|
SQL 关系型数据库 MySQL
php学习笔记-连接操作mysq数据库(基础)-day08
本文介绍了PHP中连接操作MySQL数据库的常用函数,包括连接服务器、设置字符集、关闭连接、选择数据库、结果集释放、获取影响行数以及遍历结果集等操作。通过书籍查询的实例演示了如何使用这些函数进行数据库操作,并提供了一个PHP操纵MySQL数据库的模板。
php学习笔记-连接操作mysq数据库(基础)-day08
|
12月前
|
前端开发 PHP
php学习笔记-php文件表单上传-day06
本文介绍了PHP文件上传处理流程、预定义变量`$_FILES`的使用、文件上传状态代码以及文件上传实现函数。同时,通过一个文件上传的小例子,演示了文件上传表单的创建、文件上传表单处理的PHP页面编写以及运行测试输出。
php学习笔记-php文件表单上传-day06
|
12月前
|
存储 API PHP
php学习笔记-php数组的创建和使用,数组常用函数-day03
关于PHP数组的创建、使用以及常用函数的详细学习笔记。
php学习笔记-php数组的创建和使用,数组常用函数-day03
|
12月前
|
JavaScript Java PHP
php学习笔记-php运算符,类型转换,打印输出语句相较于其他语言的特殊部分-day02
本文是第二天的PHP学习笔记,涵盖了PHP中运算符的使用、类型转换方式,以及打印输出语句的特点,展示了其相较于其他编程语言的一些特殊之处。
php学习笔记-php运算符,类型转换,打印输出语句相较于其他语言的特殊部分-day02
|
12月前
|
JavaScript 程序员 PHP
php学习笔记-php自定义函数-day05
本文介绍了PHP自定义函数的创建、调用、参数赋值以及作用域和生命周期,还探讨了`global`和`static`关键字的使用,以及`return`、`exit`和`die`的不同用法。
|
12月前
|
XML SQL PHP
php学习笔记-php字符串及字符串常用函数总结-day04
本文总结了PHP中字符串的三种定义方式和常用字符串处理函数,包括字符串的修剪、转换、长度计算、子串操作、比较、连接、分割及替换等操作。