面向对象编程思想
编程思想,面向过程,面向对象!
?
例如完成学生报名系统!
?
- 学生报到。
- 学校登记。
- 学生缴费。
- 学校收费。
- 学生选择班级。
- 班级登录学生信息。
?
一个步骤一个步骤的完善即可!
每个步骤是一个函数,通过逐一调用这些函数完成任务!
?
?
分析以上所实现的步骤:
将一个业务逻辑拆分成各个过程,分别实现各个过程,从而达到整个业务逻辑实现的目的!
称之为面向过程,类似于动词的罗列!是最基本的编程方案!
?
?
?
发现:
程序的最终目的,都是要解决真实的业务逻辑!
而且现实的业务逻辑,都是动作的主体在发出动作,而不是动作独立出现的!
?
现在面临的问题:
面向过程的编程方式,将一个罗拆分各个步骤之间组合,弱化了主体概念,主要强调步骤,和动作的概念!
而现实的业务逻辑都是由各个主体支配发生的,主体不可缺少!
?
导致:使用面向过程所编写的程序与真实的业务逻辑,逻辑关系不完全一致!从而使得面向过程的程序,不能完全的描述出真实的业务逻辑!
?
因此,如果希望使用计算机程序语言,更完善的描述去描述真实业务逻辑,明显,应该是计算机语言世界内,所有的动作多应该有主体发出!
上面的思想,就是面向对象的编程思想:是计算机解决问题的方式,尽量于现实的逻辑一致,现实的一个实体(人,物,事),应该映射成计算机语言内的一个对象!最终是计算机能够处理现实世界所有的业务逻辑!
?
因此,如果需要使用面向对象的思想实现以上的报名流程,应该:
- 分析,有哪些实体,参与了该业务逻辑
学校,学生,班级
- 通过计算机语言,实现以上三个实体
得到三个对象!
?
- 为上面的三个对象增加上相应的能力!
?
- 使用对象,调用相应的能力,从而实现业务逻辑!
?
?
面向对象是解决复杂业务逻辑的唯一出路!
?
面向对象的基本操作
基本概念
对象,object,对应现实逻辑中的一个实体,是一个实体在计算机语言的一个表示。是一个数据,与数据的操作的集合体!
属性,property,对象的数据
方法,method,对象的操作
对象怎么来的?通过实例化类而生成!
类,class,使用计算机语言对一类事物的抽象。类似于图纸!用于规定某类对象的结构,但是本身不是具体对象。
实例化,instance,依据类的抽象定义,形成对象的操作,称之为实例化!
?
//昆虫,一个定义,一类动物的抽象的概念!
基本语法
声明类,class
使用关键字 class 即可!
需要指定,该类下的实体(对象),应该有哪些特征,哪些属性,哪些操作!
例如,我们声明一个学生对象,需要先来学生类:
?
数据,称之为属性,property,属于对象(类)的变量。
操作,称之为方法,method,属于对象(类)的函数。
在声明成员时,不能直接使用变量,需要使用关键字来声明
?
实例化类得到对象,new
使用关键字 new 即可
实例化好后,典型的应该保存在变量内:
?
我只需要设计图纸(定义类),不需要参数实力话的过程。
一个类可以被实例化多次!
?
操作对象
?
使用 ->操作符,利用对象,访问其成员!
访问属性
$object->stu_name;
注意,属性名前没有$。
对当前某个对象的属性的操作,只会影响当前对象:
?
访问方法
对象->方法名();
?
?
如何在方法中,访问对象,$this
$this,这个,这个对象。调用该方法的对象!
?
$this 就是一个方法内的局部变量!特殊在,方法被对象调用执行时,php会自动确定是哪个对象调用的该方法,会使用该对象为方法内的$this赋值
?
?
tip:public,是一个访问控制修饰符,适用于控制成员(属性和方法)的访问问题!protected,private。
?
?
测试:利用面向对象编程的语法,实现学生报名的业务逻辑:
?
?
构造方法,__construct()
在实例化类得到对象时被自动地调用!
主要承担的工作是初始化对象属性!
?
对象的属性初始化
典型的,只要得到了对象,对象的属性就应该被赋予新的值!
?
如果某些属性,在对象出现时,可以被设置为某些特定的值。就可以在声明类时,为声明的属性设置默认值!
?
此处的属性的默认值,类似于参数,只能用已有值或者常量作为默认值。
?
?
还是需要很多属性初始化!
此时应该?
将初始化的工作,声明成一个方法,得到需要被初始化的数据,在方法内,对当前属性进行初始化的工作:
?
此时,在实例化对象后,调用该方法:
此时可以完成初始化!
?
如果可以在new实例化时,自动地调用上的init方法,则手动步骤也可以省略!
?
PHP会在实例化对象时,自动调用一个叫 __construct()的方法!
?
此时,如果该方法需要传递参数,则需要通过实例化时,在new cloass_name()以实参列表的形式,传递!
?
?
如果没有定义__construct()可以不用执行!
但是一旦定义了构造方法,那么构造(实例化)的过程,一定要包括这个调用构造方法的过程(构造方法一定会执行)。
?
TIP:有时也称,实例化对象为构造对象!
?
构造方法可以自动被调用!
?
?
注意
- 构造方法可以是一个别的名字
一个与类名相同的方法,也可能是构造方法!
?
此时会出现,同名与__construct同时出现的问题,__construct()会执行!
典型的兼容性的写法!防止PHP4代码运行在PHP5的服务器上的一个兼容的做法!
?
- 在new class_name时:
new Student
new Student();
取决于是否存在构造函数的必要参数!
?
?
析构方法,__destruct
与构造方法相对,表示在对象被销毁时,自动调用的方法!
对象被销毁,但是对象所占用的资源不一定完全被销毁!
?
在对象被销毁时调用,作用是,用于释放对象所占用的额外资源!而不是对象本身!
?
unset($object)
?
析构:
并不是非要有析构方法,看业务逻辑!
?
?
注意:
1对象在什么时候被销毁?
在用户脚本结束后,所有的资源包括对象都被销毁!
2保存对象的变量被提前unset!
- 保存对象的变量,被赋予了一个新的值!
?
?
预习
静态成员,static
::
类常量
self
?
继承,重写,访问权限控制
?
作业
设计一个数据库的操作类MySQLDB
?
要求:
- 在实例化对象时,就能够连接上数据库
- 在销毁对象时,关闭数据库
- 在实例化时,同样要求,设置连接字符集
- 实例化时,选择默认数据库
注意:类只是一个图纸,内声明的属性,在没有实例化对象时,是没有真实存在的!只有在实例化对象后,才会真实存在于对象内!
?
?
分析:MySQDB,的作用?
一个工具,项目中,凡是需要操作数据库,使用该工具完成!
?
设计:
应该完成那些功能,从而得到需要哪些属性!
需要的数据:主机,端口,用户,密码,字符集,默认数据库
?
需要在构造对象时,将以上的属性,设置好!
增加一个构造方法 __construct,可以接收上面的参数!
如果一个方法或者函数参数过多,或者参数不能确定时:会选择使用数组的形式完成处理:
?
在构造方法内,先完成对属性的初始化!
?
连接数据库
使用当前对象的link属性,保存当前的连接资源!
?
提示:写代码时,应该将一个独立功能封装成独立的部分,在其他地方如果需要,再对该功能进行调用!目的提高代码可重用性!
?
?
设置字符集
增加一个方法用于执行 set names charset ,在构造方法内调用!
?
选择默认数据库
增加一个方法,用于执行 use dbname SQL语句!
在构造方法内调用即可
?
测试:
?
?
升级:对参数选项增加一个默认值的概念,类似于端口,编码,可以在常规情况下实例化时省略!
在构造方法内,对属性初始化时,对默认值做处理:
?
类的静态成员,static
?
场景:
记录学生的数量!
?
当有学生类,每个学生类对象,就是一学生!
?
实例化一次,多出来一个学生。销毁一次少一个学生!
?
定义一个计数器,构造方法中数量+1,析构数量-1~
?
如何定义这个计数器?
不能直接用属于对象的属性,每个对象所独有的!
显然,应该找一个对象所共有的数据?
构造方法静态局部变量,也是不行,原因是析构不能用!
显然,应该找一个能够被对象所共有并且能够在多个方法内使用的变量?
使用全局变量即可,在方法内,是可以通过$GLOBALS访问到全局变量的!
?
此时,站在业务逻辑的角度分析下,是否合理?
全局变量不应该属于任何的对象或者类。$count 与 Student没有丝毫的逻辑上的联系!
?
显然,应该找一个能够被对象所共有并且能够在多个方法内使用的变量,还应该与当前的对象类有逻辑的关系的数据?
可以使用类的静态成员!
?
静态成员,指的是逻辑上被所有的对象所共享,属于类的成员称之为类的静态成员!
分成静态属性和静态方法
保存数据的是静态属性,执行功能的静态方法!
声明
额外增加一个 static 关键字!
属性:
方法:
?
访问
->访问对象成员
?
因此,应该使用类访问,
类 :: 成员!
::,静态访问符,类访问符(范围解析操作符)
在构造方法中,访问到,++!
类似于$this,同样存在一个self关键字(注意没有$),在类中,代表当前类!
$this:这个对象, $this->
self:类自己,self::
?
?
注意
- 访问上,静态成员只能使用::静态访问符号访问!
典型的,::前应该是类,类内可以使用self。
但是,php支持: 对象::静态成员!
尽量不要这么写!
?
- 访问上,静态成员使用类访问,而非静态成员使用对象访问。
?
但是,问题出现在方法上!
测试1,使用类访问,静态与非静态方法:
测试2,适用对象访问:
结论:‘无论是静态方法,还是非静态方法,都可以使用类或者对象来访问。那么静态方法与非静态方法的意义在于哪里?
现象的原因:方法是可执行性代码的集合,针对多个对象都是一致的!
区别在哪?
在于$this的使用上!
只有在使用对象调用非静态方法时,才可以使用$this!
静态静态方法,无论如何也不能对$this做处理
而非静态方法,只有确定了对象,才能确定$this的值!
?
?
在使用类调用对象方法时,应该注意什么问题?
?
?
?
类常量,const
在类内定义,属于类的常量!
?
定义
使用关键字const声明!
而且,没有访问修饰限定符。
?
访问
使用类访问,与访问静态成员类似:
类::常量名.
?
类中保存数据:
类常量,静态属性。
?
?
总结
类中,一共只有5种语法:
属性,方法,静态属性,静态方法,类常量
?
?
继承,extends
?
?
书,与电话都有共同的属性,可以提取!
在书,与电话中不用写:
?
怎么才能在Book类对象中,是哟个Goods类所定义的属性呢?
?
使用继承:
定义
继承:如果一个对象A,使用了另一个对象B的成员,那么我们就称A对象继承了B对象!
?
语法
使用关键字 extends 让一个类继承自另一个类!
?
tip:继承概念体现在对象上,语法体现在类上!
?
此时,特定的称谓:
Goods:父类,基础类!
Book:子类,扩展类!
?
?
语法意义就是,面向对象语法中的,代码的重用!
?
单继承
?
指的是,一个类,只能存在一个父类(基础类),不能同时继承多个类!
?
?
?
instanceof,是否是某类实例
体现:一个对象如果是子类的实例,同时也是父类的实例!(实例,通过该类实例化的对象)
?
?
?
重写,override
是个现象!
如果子类,与父类,出现同名的成员(属性方法),则在实例化子类对象时,只会得到子类中定义的成员,称之为重写!
例如,方法重写:
?
?
parent,父类
一旦重写,父类代码就不会在执行了!
?
但是有些方法是一定会重写的!
典型的构造方法:
?
怎样才能调用父类的构造方法呢?
?
parent,关键字,表示父类的意思!用于在当前类中,强制调用父类成员!
典型的做法,将参数传递到子类的构造方法中,再在子类中,强制使用parent关键字,调用父类的构造方法
?
注意:self,parent,$this的区别:
self::????????当前类本身
parent::????当前类父类
$this->????当前对象。
?
?
?
$this的确定
看上面的parent,或者是父类名:
与:
"只有在使用对象调用非静态方法时,才可以使用$this!
静态静态方法,无论如何也不能对$this做处理
而非静态方法,只有确定了对象,才能确定$this的值!"
?
$this的或的基本原因:
- 哪个对象调用方法,方法内的$this就是那个对象!
- 对象环境,是可以向下传递的!
如果当前方法内,已经确定了对象环境。在该方法内,如果出现了静态调用非静态方法,此时当前的对象环境,会传递到被静态调用的非静态方法中!
?
?
?
问:$this永远代表所在类对象么?
不是!
?
访问修饰限定符,public,protected,private
public,公共的
protected,保护的
private,私有的
?
用于描述,一个成员(属性,方法)在哪里才能被访问的!
?
注意:
PHP是采用类的概念,进行成员的限制访问的!
PHP将访问的代码,分成三大区域:类内,类外,继承链上类内!
?
是根据:
成员在哪里定义与成员在哪里访问来决定类内,类外还是继承链上类内!
以属性 $property为例:
?
?
public
公共的,指的是,成员在本类内,继承链上的类内,与类外,都可以被访问!
?
?
protected
保护的,指的是,成员在本类内,继承链(子类,父类)上的类内可以被访问
?
private
私有的,指的是,只有本类内,可以访问!
?
?
?
如何选择:
一个原则,尽量体现封装性。封装性,指的是,尽量隐藏内部实现,而仅仅开发外部操作接口!
语法上,就是,将不需要外部使用的属性,方法,都私有化(保护化),而仅仅留下一些必要的公共方法!
?
?
注意
- 重写的问题,一定要先明确访问的究竟是哪里所定义的!
- 私有成员的重写问题。
私有成员不能被重写。意味着,在相应的私有属性定义的类中,才能访问到相应的私有属性!
?
注意,在处理私有属性时,一定要确定其定义位置!
?
建议是
如果需要通过继承,你就使用保护的,少用私有的!
在没有继承时,尽量使用私有的!
?
?
- 在重写时,如果重写成员的访问级别不一致。
子类的级别比父类的级别,相等或者弱,可以!
强,不行!
?
?
- 兼容性的问题
早先的 php的面向对象不完善,没有访问控制!
在声明属性时,使用 var 关键字!
声明方法时,什么都不使用!function
?
为了兼容,上面的做法还是可以使用!
?
var,function。访问权限都是 public的!
?
?
冒泡排序
相邻的两个数比较,大数向后走!
模拟
待排序序列:
24 |
11 |
67 |
10 |
9 |
23 |
45 |
11 |
24 |
67 |
10 |
9 |
23 |
45 |
11 |
24 |
67 |
10 |
9 |
23 |
45 |
11 |
24 |
10 |
67 |
9 |
23 |
45 |
11 |
24 |
10 |
9 |
67 |
23 |
45 |
11 |
24 |
10 |
9 |
23 |
67 |
45 |
11 |
24 |
10 |
9 |
23 |
45 |
67 |
11 |
24 |
10 |
9 |
23 |
45 |
67 |
11 |
10 |
24 |
9 |
23 |
45 |
67 |
11 |
10 |
9 |
24 |
23 |
45 |
67 |
11 |
10 |
9 |
23 |
24 |
45 |
67 |
11 |
10 |
9 |
23 |
24 |
45 |
67 |
? | ? | ? | ? | ? | ? | ? |
?
?
明显,需要N-1轮就可以排序出来结果!
每轮内,需要对余下的元素依次做相邻的元素之间的比较!
?
计算关系:
$total = 7;
轮数 |
参与比较次数 |
比较 |
? |
1 |
6 |
0,1|1,2|2,3|…|5,6 |
0-(7-1)-1 |
2 |
5 |
0,1|1,2|…|4,5 |
? |
3 |
4 |
0,1|…|3,4 |
? |
。。。 |
。。。 |
? | ? |
6 |
1 |
0,1 |
? |
?
公式:
比较次数 = 总元素个数-轮数!
?
其次,需要控制那两个元素参与比较?
确定第一个参与比较的元素即可:
从0 到总元素个数-1-当前轮数
?
交换元素位置,找到第三个变量!
?
编程实现?
双层循环,外层比较轮数,内层控制比较元素下标!
?
排序就是消灭逆序的过程!
?
预习
final,抽象,接口
序列化
自动加载
单例模式,工厂模式
作业
- 要求升级mysqldb,尽量体现封装性!
- 升级mysqldb,提取执行SQL的方法,凡是执行SQL,都需要调用该方法实现!
- 要求增加 fetchAll的方法,功能时得到一条查询类的sql语句,返回所有的结果数组!
4,练习,比赛列表其他都是mysqldb来完成!
作业回顾
mysqlDB的封装性
?
都封装起来了,需要对其修改,或者获取去信息,应该怎么办?
?
为,需要在外边访问的成员属性,增加一对接口(公共)方法,便于操作!
?
?
原则
禁用所有,开放特定!
?
?
提取执行sql语句的方法!
?
在执行SQL时,使用该方法:
?
?
fetchAll
?
?
?
类:实例化对象
类:调用其静态成员
类:作为其他类的基础类,被继承!
?
两大功能:
1,实例化对象。2,基础类被继承!
?
存在两种特殊的类,功能单一!
- 只能实例化对象,不能被继承。
- 只能被继承,不能实例化对象。
?
final类,final方法
final类
final,最终,在继承链条上最末的一个类!其下不能再出现子类,意味着不能被继承!
?
例如,认为,Book类的对象就是所有图书对象,不能再出现故事书,小说等等书的子类!
?
final,并没有增加额外的功能!意义是,在语法上限制某个类不能被继承!从而保证数据的完整性!
?
final方法
final关键字还可以限制方法!
可能出现final方法!限制方法是否能被重写!
抽象类,abstract类
抽象类:包含了抽象方法的类称之为抽象类,不能用于实例化对象,只能被继承!
抽象类,不完整的类,由于包含了不完整的方法。
不完整的方法,也叫抽象方法,指的是没有方法体的方法,称之为只有方法的声明,而没有方法的实现的方法称之为抽象方法。也就是不完整的方法!
?
需要使用关键字 abstract来声明这个抽象方法与抽象类!
?
不能实例化对象
?
注意:抽象类是可以包含其他任何正常的成员的,在此基础上,增加了内部的抽象方法!
(并不是抽象类中只能包含抽象方法)
?
只能被继承
但是,继承时,要求,如果子类不是抽象类,那么继承的抽象方法,要被实现(被加上方法体)才可以!
?
使用意义
可见,抽象类,可以规定其非抽象子类,必须要存在的相应成员方法!
可以规定,子类中都必须存在,但是可以不同的方法!
?
?
几个概念:
抽象:abstract,不完整的意思!举目张刚的意思!
实现:implement。将方法完整化!
?
?
接口结构,interface
接口,指的是对象的公共方法。
也有一种接口技术,定义一个接口结构,用于限制一个类(对象)因该具备的公共方法(接口方法)!
?
?
语法:
?
声明
使用关键字 interface声明一个接口结构!
注意,接口内只能包含公共的抽象方法(不完整的方法)!
?
使用
使一个类来实现接口内所定义的所有接口方法(公共方法)
实现,使用关键字:implements来完成
明显,实现该接口结构的类,就包含了接口中定义的抽象方法,两个选择,1,定义成抽象类,2是实现接口方法!
?
?
类似于抽象类,比较与接口的区别:
- 抽象类与普通类之间是继承关系!
普通类继承抽象了,第一可以得到抽象类中的已有的常规成员,第二才需要实现抽象方法(也不一定是public的)
- 接口与普通类之间是实现关系!
普通类实现了接口,只能将其没有实现的公共方法实现!
?
- 接口只用于定义公共的方法!而抽象类,什么都可以有!
?
典型的使用:
?
?
多实现
一个类,可以同时实现多个接口
?
?
?
接口可以定义常量
?
?
辨别?
- 接口是不是类?
接口不是类,接口就是独立的一种结构,适用于限制类的结构!但是可以理解成"接口类似于一个所有的方法都是公共的抽象方法,而且没有其他成员的抽象类",但完全不是一个概念!
class_exists();判断一个类是否存在?
- php是单继承,怎么实现多继承?
"可以通过接口的多实现来模拟"
不能实现多继承!
?
?
类文件的载入-自动加载机制
项目中如何管理大量的类的定义?
典型的,每个类,独立的创建一个文件,用于保存定义该类的源代码!使用时,将该文件载入即可!
此时,类文件的命名为:
类名.class.php
?
此时,面临一个类文件很多,某个功能需要使用其中不分类:
如何合理方便载入?
?
老办法:
将载入类的代码,放在一起:
问题是,会有类的额外加载!
?
现在的载入类文件的方式是?
按需加载
?
在需要某个类时,如果该类没有被加载,则加载定义该类的类文件!
?
判断当前类是否已经加载?
该类在哪个文件中?
什么时机执行上面的操作?PHP本身解决
?
此时可以使用PHP的类文件,自动加载机制完成!
?
自动加载机制
当需要一个类,当时并没有找到该类的定义,此时,PHP核心(Zend Engine),会自动尝试调用一个叫:__autoload()的函数。与此同时,会将当前所需要的类名作为参数,传递到__autoload()这个函数中。
?
默认是没有这个函数的,需要用户自己定义!
?
因此,用户脚本,需要完成定义该函数:
该函数应该有个形参,用于得到当前所需要的类名!
?
此时,我们只要,完成该函数,利用得到的类名,将类名所对应的文件载入即可!
?
分工:
用户脚本:定义函数,接收需要的类名作为参数,函数需要实现通过类名找到类所在的文件,将其载入即可!
PHP核心:判断是否需要类,并且判断该类是否已经载入了,如果需要但是没有载入,则尝试调用用户定义的__autoload()函数,并将需要的类名传递即可!
?
?
分析:
__autoload函数获得是类名
而载入的是类的定义文件
因此,自动加载机制的大前提:必须要能够通过类名,推导出,类定义所在的文件才可以!
因此,要求大家在定义类文件时,要有规律!
?
类文件 = F(类名)
?
?
序列化,反序列化
串行化,反串行化
?
场景。
数据的持久性保存!
?
例如,将数据保存在文件:
向文件写入数据:
写入的长度 = file_put_contents(‘文件‘, ‘数据‘);
从文件读取数据:
数据 = file_get_contents(‘文件‘);
?
?
在数据保存,面临一个问题:
数据格式的问题。
?
PHP的数据有八种类型之多,文件只能存字符串!!
?
一旦数据类型不是字符串类型!就会导致数据不能原样保存,不能取得原始数据!
?
因该如何解决?
任何形式的数据,都可以存储到文件中,并且,在取出来时,原样得到数据!
?
在保存,与读取时,对数据进行转换与反转换!
?
?
序列化,serialize
原始数据转成能够记录原始数据信息的字符串!
?
反序列化,unserialize
通过序列化的字符串结果,将原始数据还原!
?
?
只有在涉及到,数据需要被,存储,或者传输时(),需要对数据进行序列化!
?
?
注意的数据类型都可以被序列化与反序列外。资源是例外!
例如:
其他可以!
?
?
对象的序列化与反序列化
- 在反序列化时,需要找到该对象所属的类的定义才可以,否则会变成__PHP_Incomplete_Class类的对象,不是原来的对象:
存入:
读取:
?
因此,只要在反序列化之前,将类载入即可!
?
?
- 反序列化,也会触发自动加载机制。
?
?
- 在序列化时,可以自定义需要序列化的属性名单!
通过对象的特殊的方法__sleep()
该方法会在对象被序列化时,自动调用,不需要参数,需要返回一个数组,每个元素,表示一个属性名,数组内存在的属性名,就会被序列化。反之则不会被序列化!
?
- 在反序列化时,可以自动再次执行某些代码,从而完成某些资源的初始化!
通过对象方法:__wakeup()方法
会在对象被反序列过程中自动调用,所负责的功能,执行反序列话(醒来之后)的初始化工作!
?
?
?
总结:
__construct
__destruct
__sleep
__wakeup
?
php自动调用,用户脚本只需要定义。在特定的功能调用特定的方法!
总称为:魔术方法;
?
?
?
对象的拷贝
对象之间的赋值,只有引用传递,没有值传递!
保存对象的变量内,保存的不是对象本身,而是对象的标识!
?
导致的结果,不能通过赋值的方式,使用旧对象,得到新对象!
?
对象的克隆
克隆,使用一个已有对象,得到一个属性一致的新对象!
使用关键字 clone 来实现
?
典型在克隆时,一定会出现某些属性时用于区分是否是克隆出来的!
?
意味着,在克隆出来新对象时,要为新对象增加一些额外的标识才可以!
此时,在执行clone时,会自动调用新对象的魔术方法 __clone,去完成克隆对象的额外的初始化工作!
注意,$this是新对象!
?
预习
设计模式,单例模式,工厂模式
重载,属性方法重载
魔术方法
反射机制
作业
- 增加mysqldb类的fetchRow方法
类似于fetchAll,执行一条查询类的sql,返回符合条件的第一条记录!
?
$sql = "select * from select-student where id=10";
$row = $db->fetchRow($sql);
$row = array(‘id‘=>10, ‘stu_name‘=>‘张无忌‘, class_id=‘10‘);
- 增加mysqldb类的fetchColumn方法
类似于fetchRow,执行一条查询类的sql,返回符合条件的第一条记录的第一个字段值!
select count(*) from student
$result = $db->fetchColumn($sql);
$result = ‘23‘;
?
?
3,使用mysqldb工具类,全面改善match功能!
单例模式
单例,单个实例。设计模式的一种,通过一种语法的设计,保证类(对象)上具有某些特征,这样的一种语法实现,就可以称之为设计模式!
其中,设计可以保证一个类,有且只有一个对象,这种设计模式就称之为单例模式!
单例模式的作用,单例的设计,是适用于使用一个对象可以完成所有业务逻辑的类
?
典型的实现,在类上,做限制:三私一公!
某个类只要实例化一次就可以完成所有的业务逻辑!
但是实例化多次也可以。
?
显然,应该保证对象被实例化一次,从而节约资源空间!
?
例如,当前的MySQLDB类!
?
那么,如何去设计这个MySQLDB类,从而达到保证该类有且只有一个对象?
原因就是使用者,可以无限次地去实例化这个类new!
?
解决步骤,三私一共
- 限制,用户无无限制执行new!
在实例化的过程中,需要执行构造方法,如果构造执行不成功,那么实例化过程失败!
因此:将构造方法,私有化(保护化),可以保证在类外进行实例化的工作都会失败!
- 类,不能实例化了,不能在类外实例化了!可以在类内实例化,类内执行new操作!
?
因此:在类中,增加一个公共的静态的方法,在方法内,执行new实例化类对象!
?
- 看似又回到了原点,可以无限制的调用getInstance得到任意多个对象!但是此时得到对象都需要经过 getInstance,我们可以在getInstance内,增加限制,使用户得到对象的改变!
方案如下:在实例化好对象后,将对象存起来,下次再执行时,判断是否已经有保存的,有了,直接返回已经存在的,没有,实例化后,保存起来,再返回!
增加一个私有的静态属性,在 getinstance内做判断
?
此时,无论调用N次,getinstance,都得到一个对象:
?
?
- 此时,还可以通过克隆来得到新对象!
私有化__clone()方法
?
?
?
注意,在单例时,为构造方法传参的问题:
?
?
?
在项目的设计层面解决单例的问题
?
增加一个实例化的方法(函数)
希望,用户如果想要得到单例对象,就通过调用该函数完成!
?
?
?
优点,灵活,可以针对多个类同时实现单例,而且,类还可以回归到非单例的效果!
?
重载
重载,重新加载!
?
重载,overload,指的是php对当前对象的不可访问成员的处理方式!
其中,不可访问:指的是两种,不存在的和受到访问控制访问不到的!
默认的处理方式:
- 针对不存在的属性:
自动增加属性为公共的属性!
- 针对访问权限限制的:
?
上面的默认的处理方式都是可以有更改的余地!
?
属性重载的魔术方法
属性的重载处理,需要使用php提供的魔术方法完成
因此,有四个魔术方法,用于分别处理上面的情况:
__set();
当为不可访问的属性赋值时,会被自动调用
会得到两个参数,当前操作的属性名,和属性值!
典型的,__set的作用,用于严格控制对象结构,和批量处理可以被修改的属性!
?
?
__get();
当访问不可访问的属性时,会被自动调用
需要的参数是:一个,为当前操作的属性名
?
__unset()
在删除一个不可访问的属性时,可以自动被调用!
需要一个参数当前操作的属性名。
此时就可以利用业务逻辑完成属性的删除处理!
__isset();
在判断一个不可访问的属性是否存在时,被自动调用
需要一个参数,属性名
注意,次函数需要返回true,或者false,表示属性是否存在:
?
?
在很多其他语言中,重载,指的是重复加载!
?
方法重载的魔术方法
__call()
当访问一个不可访问的对象方法时,会触发当前的魔术方法!
此时会触发:
需要的参数时:
2个参数,第一是当前的方法名,第二是调用时使用的实参列表!
?
典型的作用,
- 给出友好的提示
- 执行默认操作!
static __callStatic()
与 __call类似,当静态调用一个不可访问的方法时,会自动执行!
?
?
魔术方法,magic method
在特定的情况下,会被自动调用的方法,通常负责完成某块独立的功能的方法称之为魔术方法!特点:1,需要用户脚本定义,不定义不执行!2,命名方式都是以__开头!
?
总结:
__construct
__destruct
__sleep
__wakeup
__set
__get
__isset
__unset
__clone
__call
__callStatic
?
__autoload()//魔术函数
?
?
?
__invoke()
将一个对象,当作函数调用时,会触发该对象的__invoke()方法,由此方法,就可以调用,没有该方法就不能调用!
?
回想匿名函数
$say中是啥?对象!
语法是调用对象的语法?
为什么,匿名函数对象(ClosureL类对象)可以,但是普通类对象不行?
?
__invoke是 php实现匿名函数不可或缺的部分!
?
此时,也可以传递参数,为对象传递参数,就是为invoke魔术方法传递参数!
?
__toString()
转换到字符串的意思!
当将对象当作字符串使用时,会自动调用该对象的魔术方法!
如果此时,存在toString 魔术方法,即可以完成转换。
toString的返回值,就是转换的结果,一般转换对象的标志性的属性即可!
?
?
?
静态延迟绑定,static
>=5.3
问题:
- $this永远代表所在类的对象?不是
- self用于代表所在类么?
是,永远代表所在类的对象!
?
看逻辑:
显然,当前的逻辑不是十分完善!
?
此时,应该是表示当前类的关键字,最好应该在调用时决定最好!(self不能做到)
?
此时,采用一个新的关键字,代表当前类,与self不同,在于是运行时调用时决定,而不是在类编译时就确定好了的!
关键字是: static。
?
?
?
总结:
static关键字的功能:
- 声明静态局部变量
- 声明静态成员
- 当前类,运行时的当前类!
?
类中,可以表示类的关键字:
self,所在类
static,调用类
parent,父类
?
?
参数类型约束
约束函数,或者方法类参数的类型,只能是某个类的对象!
?
php是弱类型,变量可以存储任意类型的数据!
函数,方法的参数也是可以接受任意类型!
?
但是参数,可以被规定为,某个类的固定对象!
在参数前增加类名即可!
?
注意,只支持类名!
?
?
还支持数组!
?
?
对象的遍历
对象是一个集合数据类型!
简单的遍历,foreach
foreach,可以遍历对象
遍历对象,是依次获得对象拥有的属性的信息!
留意,访问修饰可以影响!
?
自定义遍历,iterator,迭代器接口
场景:在遍历班级时,就相当于,遍历的班级的所有学生,而不不是遍历班级的所有属性!
?
此时,需要使用接口编程实现。
?
foreach时,php回去判断当前所遍历的对象的类,是否类实现一个叫 iterator(迭代器) 接口!
不是的话,就会依次得到对象每个属性!(简单遍历)
是的话,会在foreach执行时,通过调用接口内规定的各个方法来完成这个遍历!
?
两个问题:
foreach的流程:
Iterator接口的内容:预定义的!php定义好了的!
显然,php的foreach的五个重要的步骤,依赖于接口中定义的5个方法!
?
编程实现,是需要遍历学生信息:
- 类要实现Iterator接口
2依次完善抽象方法
?
?
常用的对象,类函数
is_object();
class_exists();
interface_exists();
get_class();
get_parent_class();
?
get_class_vars();得到类的变量(属性)
get_class_methods();得到类的方法
?
get_declared_classes();得到所有已经定义的类!
可以见,有自定义类,和预定义类!
stdClass,内置的标准类!
__PHP_Incomplete_Class
Closure
?
?
魔术常量
__CLASS__,当前类名。注意:可以new self不可以new __CLASS__。
__METHOD__,当前方法名。区别__FUNCTION__。
__FILE__
__DIR__
__LINE__
__FUNCTION__
?
?
面向对象的特征
封装,
?
继承
?
多态
?
?
快速排序
分治。分而治之!
核心思想:解决一个难度为N的问题,与解决2个难度为N/2 相比!
?
冒泡解决 6个元素的问题?
需要比较几次?
5,4,3,2,1 = 15
?
冒泡 3 个元素的问题两次?
2,1 = 3
2,1 = 3
?
思路:
将整体的待排序序列,分割成两个部分!分割的原则,跳出一个参考元,将比参考元大的,放一起,比参考元小的放在一起!假设第一个为参考元!
?
接下,再对,分割的两个子序列,再次分割!
直到所有的分割的待排序序列内,元素数量为一个或者0个!
?
?
实现的时候,应该注意:1,选择参考元的问题。
?
编程实现:
递归实现!
递归点:
递归出口:待排序的序列元素个数为1或者0,则不需要再递归了!
?
步骤:
- 判断是否是需要再次递归(递归出口)
- 选择参考元(第一个元素)
- 将数组分割成两个部分。
- 递归对分割的两个部分进行分别排序
- 将小于与参考元与大于三个部分合并起来!
?
作业
- 将MySQLDB改写成单例的三私一共的!
- 总结所有的魔术方法
名字 |
作用 |
触发时机 |
获得的参数 |
__set |
属性重载,设置属性 |
不可以访问属性赋值 |
属性名字,属性值 |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
?
面向对象所有的关键字:
关键字 |
功能 |
示例 |
? |
New |
实例化 |
New class_name; |
? |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
? | ? | ? | ? |
?
- 思考题
一个10层楼,电梯。
每层的电梯门口,都摆放了一堆钱,但是数量不一致!
问题,从1到10.每层打开门一次,在10次中,可以去拿起一次钱!
问题,怎样才能拿到最多?
?
?