面向对象编程思想简介
什么是编程思想?
所谓的编程思想,就是人们用计算机来解决实际问题的时候的一种思维方式,或者说是一种基本的策略;
常见的编程思想有面向过程和面向对象,很多语言的语法各不相同,但是,基本的编程思想却是差不多的!
PHP同时支持面向对象和面向过程两种编程思想的语言!
面向过程的编程思想
传统的面向过程的编程思想总结起来就八个字——自顶向下,初步细化! 基本策略如下:
ü将要实现的功能描述为一个从开始到结束的按部就班的连续的“步骤”(面向过程)
ü依次逐步完成这些步骤,如果某一个步骤的难度比较大,又将该步骤再次细化为若干个子步骤,依次类推,一直到结束得到想要的结果!
ü程序的主体是函数,一个函数就是一个封装起来的模块,每个模块都可以实现特定的功能,各个子步骤往往就是通过各个函数来完成的,从而实现代码的重用和模块化编程!
案例:大家去学校“报名上学”这件事,可以分成哪些步骤?
所谓的面向过程,就是将上面分析好了的步骤,依次执行就行了!
面向对象的编程思想
所谓的面向对象,就是在编程的时候尽可能的去模拟现实世界!
现实世界中,任何一个操作(动作)或者是任何一个业务逻辑的实现都需要一个实体去完成,实体就是操作(动作)的支配者,没有实体,就没有动作发生!
思考:上述报名的每一个步骤都有哪些动词?
提出 提供 缴 分配 增加
有动词就一定有实现这个动词的实体!
所谓的模拟现实世界,就是使计算机的编程语言与解决相关的业务逻辑的时候,与真实的现实世界中的业务逻辑的发生保持一致!需要使某个动作都是依赖于一个实体的“动作/操作/行动”,可以看做是一个一个的实体在发挥其各自的“能力”并在内部进行协调有序的调用过程!
如果采用面向对象的思想,解决上面的报名的问题应该如下:
1,分析哪些动作是由哪些实体发出的!
提出 提供 缴 分配 增加
学生提出报名->学生缴费->学校收费->老师分配教室->班级增加学生信息
于是,在整个的报名过程中,一共出现了多少个实体?
四个:学生、x学校、老师、班级
在现实中的一个具体的实体,就是计算机编程中的一个具体的对象!
2,定义这些实体,为其增加相应的属性和功能(功能就是能完成的动作,在面向对象的专业术语中叫作方法,其实也就是函数)
1,让实体,去执行相应的功能或动作!
学生提出报名
学生缴费
机构收费
教师分配教室
班级增加学生信息
班级管理学生信息
所以说,面向过程主要是针对功能,但是面向对象主要是针对能够实现这些功能的主体(实体)
从面向过程到面向对象编程思想的转变
以前写代码,首先想到的是需要实现什么功能——可以调用系统函数,也可以自己定义函数,或者按部就班的执行!
以后写代码,首先想到的是应该有什么样的实体(主体)去完成什么样的功能,再把这些实体的属性和功能进行封装,最后才去实现这些实体的功能!
面向对象不是一种技术,而是一种思想,是一个解决问题的最根本的思维方式!
所以,面向对象的核心思想是:不仅仅是简单的将某些功能进行封装,而是对调用该功能的主体进行封装,如果一个实体拥有多个功能的话,在使用的过程中,先得到相关的对象,再使用对象去调用其相关的功能!
面向对象与面向过程的对比
1,都可以实现代码重用,以实现模块化编程,但是面向对象的模块化更深,数据更封闭,也更加安全!
2,面向对象的思维方式更加贴近现实生活,所以也更容易解决大型的复杂的业务逻辑!
3,从前期开发的角度来看,面向对象比面向过程要复杂的多,但是从维护和升级的角度来看,面向对象远比面向过程简单!
面向对象基本概念
面向对象的阶段概念
OOA:面向对象分析、OOD:面向对象设计、OOP:面向对象编程
对象的概念,什么叫做对象,object,现实业务逻辑中的一个动作实体,就对应着OOP编程中的一个对象!
所以:
对象是采用属性(property)来保存数据!
对象是采用方法(method)来管理数据!
对象如何产生呢?又如何规程对象的属性和方法呢?
在PHP中,对象是由类实例化而来的,也就是说,在PHP中,要想产生一个对象,必须先有一个类!
什么是类?
类其实就是得到对象的一种方法而已!只不过在大多数的面向对象编程语言中,都是通过类来产生对象,但是,也有的面向对象的语言,产生对象的时候是不需要类的!
为什么要引入类的概念?
其实类本来也是对现实世界的一种模拟,在现实世界中,任何一个实体都有一个类别!
类就是具有相同或相似的特征特性的该类事物的一个通用的名称!
比如:我们都属于人类,人类又都属于灵长动物类,灵长动物类又都属于动物类,动物类又都属于生物类!
所以,在php中,一个对象是指现实中的一个具体的实体,而既然现实中的每一个实体都有一个类别,所以OOP中的对象也应该都有一个类!
一个对象的所有应该具有的特性特征信息,都是由其所属的类决定的!但是每个对象又很有可能有自己不同的特征特性信息,比如我自己这个对象名字叫圣骑士,性别男,会写程序,会教书;另外一个对象可能叫章子怡,性别女,会演戏!
类的定义
使用class关键字来定义的!
这就是一个类,只不过里面什么都没有!
其中,类名不区分大小写,由字母数字和下划线构成,第一个不能为数字,一般类名采用大驼峰法命名(主要是区别方法名或函数名,我们一般使用小驼峰法来表示函数名和方法名)
思考:类中可以有什么呢?
先回忆一下以前面向过程中,我们的代码有什么?
定义常量和变量、定义函数
使用变量和常量(增删改查)
调用函数、流程控制(if—else for while do-while 、foreach等)
语法上,一个类的内部可以具有自己的“变量”和“函数”,但此时技术术语上应该称为“属性”和“方法”,而且,一个类也可以有自己的常量(类常量),
上面的属性、方法、常量就称之为是类的“成员”!
所以,定义一个类,其实就是定义三种成员:定义属性(变量)、定义方法(函数)、定义常量(类常量)
一个需要注意的地方就是,需要对成员进行声明才可以使用!
声明采用的是访问修饰限定符来声明的,一共有三个:public,protected,private,暂时全部用public来声明,其中另外两个后面才学习!
有两个特殊的:
1,public可以用var来代替!只是对低版本的一种兼容!
2,方法的前面可以省略掉访问修饰限定符!默认的就是为public
相当于:
上面就定义了一个含有名字和Money金额和一个缴费方法的学生类!
注意,在定义类的时候,如果没有给某个属性赋值,默认的就有null型,但是如果给其附上一个初始值,就必须是一个“直接值”,不能是一个表达式计算后的值!
利用类得到对象
注意:类本身什么都做不了,必须利用类得到对象,这个过程就叫作类的实例化!
类的实例化是通过关键字new来完成的!
语法是:new 类名;
上面已经实例化了一个对象,不过对象一般都是放到一个变量里面!
对象如何访问?使用箭头-> 实现对对象成员的访问!
可以实例化多个对象:
对象的编号不同,就说明它们占用不同的内存空间!
instanceof运算符
可以利用instanceof运算符来判断某个对象是否是由某个类实例化而来的!
方法中$this关键字
$this是一个“伪对象”,代表当前所属的类的当前对象!
$this的自我告白:谁调用我,我就属于谁!
思考:属性和方法都属于对象的成员,为什么访问属性的时候不需要$this关键字呢?
再次强调:属性不能在方法内直接访问!需要找到其对象才能访问,一个典型的做法就是使用$this->属性名来访问当前对象的属性
构造方法
通常实例化完一个对象后,都要对对象的属性进行初始化才有意义
也就是说,每次实例化完一个对象后,都要对该对象进行一次初始化操作!比较麻烦!
思考:如何改善?
可以类中建立一个专门给属性进行初始化的方法,实例化完之后,直接调用这个方法,一次完成对象的属性的初始化!
上面的代码可以完成对象的属性的初始化,但是还是不够方便,每一次new完一个对象后都必须手动调用init方法才能进行属性的初始化工作!
如果new的时候,能够自动调用init是最好的!
于是,构造方式就横空出世了!
事实上,在实例化一个对象的时候,php会自动的调用一个名字叫__construct()的方法!
该方法,由于专门负责对新对象进行初始化,称之为“构造方法”!
该方法的最大的特点是,不需要人为的手动调用,而是由系统在实例化一个对象的时候自动调用!
问题是,调用该方法的时候如何将实参传递给该方法的形参呢?
需要在实例化对象的时候顺便在类名后面增加一对小括号,里面传递实参列表
注意:
在php早期版本当中,构造方法有一个比较老的语法,就是使用和类名相同的方法作为构造方法!
1,如果既有老语法的构造方法名,又有新语法的构造方法名,系统会主动调用__construct方法!
2,存在一个最兼容的写法:
析构方法
概念:与构造方法是一对,构造方法是 在一个对象“出世”的时候由系统自动调用的!而析构方法是在一个对象“消失”的时候由系统自动调用的!
名字是:__destruct() 注意:该方法里面不能有参数!
思考:析构方法是在对象消失之前调用的还是对象消失之后调用的?
对象消失的几种情况:当一个脚本周期结束的时候,明确的使用unset去删除一个对象的时候,改变对象变量的值,也会自动销毁!
析构方法的作用
注意:析构方法主要的作用就是释放对象所占用的额外的资源,而不是对象本身
我们应该在对象消失的时候,增加析构方法,释放该对象占用的额外的 资源
注意:析构方法通常都需要需要额外的定义,只有在对象执行的过程中,占用了额外的资源的时候才使用!
总结一下构造方法和析构方法的特点:1,都是以__开头 2,都是由系统自动调用 3,都是某个特定的情况发生的时候,调用相应的方法!
对象的传值与克隆
对象的传值
值传递
引用传递
所以,对象的值传递和引用传递其实效果是完全一样的!
也就是说,对象间的复制,无法开辟一个新的对象空间,有时候,也叫作“浅复制”!
那么,我们如何利用一个已有的对象,得到一个新的对象呢?(单独开辟内存空间)
这个时候就需要使用对象的克隆!
对象的克隆:所谓的克隆,不是通过类的实例化得到新的对象!而是通过一个已有的对象得到一个新的对象!语法如下:新对象 = clone 对象
克隆一个对象的时候,会不会触发构造方法?
回答:不会!因为构造方法只有在实例化一个对象的时候才会触发,但是克隆一个对象不是实例化!
但是,存在一个克隆对象的时候自动调用的魔术方法!
__clone方法
该方法就是在克隆一个对象的时候,负责对新对象进行相关的初始化!
为什么要有__clone方法?
很有必要,因为客观世界不存在两个完全相同的对象!