Alan Hou的个人博客

PHP面向对象的三大特性

面向对象的三大特性:封装性、多态性、继承性

封装性

封装性就是把对象的成员(属性,方法)结合成一个独立的相同单位,并尽可能隐藏对象的内部细节。
PHP中的访问修饰符包括:public,protected,private,
private私有的, 用这个关键字修饰的成员,只能在对象内部访问(只有用$this访问),不能在对象外部使用

protected受保护的, 用这个关键字修饰的成员,只能在对象内部及子类中访问,不能在对象外部使用

public公共的,顾名思义,无论是内部,子类中还是外部都可以被调用

属性的封装
只要一个变量,需要在多个方法使用,就将这个方法声明为成员属性,可以直接在这个对象中的所有方法中使用。成员属性就相当于这个对象中的全局变量。
成员属性都会在方法中使用, 成员属性值的变化其实就是在改变方法的执行行为, 也就是改变了对象的功能。成员属性的值如果不正常, 方法执行的功能也就不正常了

作用:控制某些属性的值不能在对象外部被改变或读取
若允许修改但要进行一定的控制可以先封装,再提供一个公共的方法(经过方法对象成员属性进行赋值和取值就可以控制)

方法的封装

作用:
1. 使用private修饰使用其只能在内部使用
2. 假如一个类中有100个方法, 封装了95个(为另外的5个服务的方法), 只有5个方法可以使用

和封装有关的魔术方法:
__set():是直接设置私有成员属性值时,自动调用的方法
__get():是直接获取私有成员属性值时,自动调用的方法
__isset(); 是直接isset查看对象中私有属性是否存时自动调用这个方法
__unset(); 是直接unset删除对象中私有属性时,自动调用的方法

继承性

继承性具有以下特性:

1. 开放性、可扩充性
2. 增加代码的重用性(通过继承父类中的属性和方法)
3. 提高了软件的可维护性(在父类中统一修改或添加属性或方法)
4. 继承就是用子类(又称派生类)去扩展父类(又称基类)

C++ 属于多继承,即 同一个类可以有多个父类,PHP和Java属于单继承, 即同一个类只能有一个父类。不论多继承还是单继承都可以有多个子类,只要在设计两个类时,有可以共享的成员,就可以将共享的内容拿出来,单独作为一个父类(基类)使用。

一、类继承的应用
1.     声明一个子类,使用 extends 关键字去继承(扩展)一个父类(class a extends class b)
2.  子类可以从父类中继承所有的内容,包括成员属性,成员方法, 构造方法,析构方法等, 并且在子类中都可以直接使用
3. 最重要的是将父类子类之间的层次关系设计好
二、访问类型控制
虽然子类可以从父类中继承所有内容,但private成员只能在本类中使用, 子类中也不能使用。封装时,若需既可以让自己类的内部可以访问,也让子类可以用,但类的外部不能使用,只需将关键词 private改为protected。
三、子类中重写父类的方法
1. 子类可以声明和父类相同的方法名,即子类覆盖了父类中同名的方法(参数数量也需一致)
比如子类鸵鸟继承父类鸟类飞的方法, 需在鸵鸟类中将飞的方法改写,也就是子类的方法对父方法的扩展。
在子类中调用父类中被覆盖(重写Override)的方法为父类名::方法名(),使用parent::方法名()可以保证在父类类名修改后还可以正常调用。
(对象->成员  类::成员)

在子类中编写构造方法,如果父类中也有构造方法一定要去调用一次父类中被覆盖的那个构造方法(parent::__construct())。
注意: 子类中重载的方法,不能低于父类中访问权限(private,protected,public), 子类可以放大权限,但不能缩小权限

PHP中常用的关键字

final
1. final不能修饰成员属性(不同于Java,类中常量不是用这个关键字)
2. final只能修饰类和方法
作用:
使用final修饰的类不能被子类继承,使用final修饰的方法不能被子类去覆盖,因而限制类不被继承,方法不被覆盖就使用final
static
1. 使用static可以修饰成员属性和成员方法,不能修饰类
2. 用static修饰的成员属性,可以被同一个类的所有对象共享
3. 静态的数据是存在内存中的 数据段中(初使化静态段)
4. 静态的数据是在类每一次加载时分配到内存中的, 以后再用到类时就直接从数据段中获取
5. 什么是类被加载? 只要在程序中使用到这个类(即有这个类名出现)类就被加载
注意: 静态的成员都要使用类名去访问(类名::静态成员),不用创建对象, 不用对象去访问
如果在类中使用静态成员, 可以使用 self代表本类(类似对象中的$this),这样即便修改类别依然不会有问题
6. 静态方法(static修饰的方法), 不能访问非静态的成员(在非静态的方法中,可以访问静态成员)。因为非静态的成员必须用对象来访问,访问内部的成员使用的就是$this,静态方法不用使用对象来调用, 也就没有对象, $this也就不能代表什么对象, 非静态的成员还必须使用对象,就产生了予盾
如果你确定一个方法不使用非静态的成员, 则可以将这个方法声明为静态方法(优点是不用创建对象,直接使用类名就可以访问)
静态成员使用“类名::成员”访问 , 在类内部访问其它成员“self::成员”
const
1. const只能修饰成员属性
2.php声明常量使用define(“SITE”, “alanhou.org”), 但类中声明常量属性使用const
3. const命名的方式和以前学习的define是一样的效果
4. 其访问方式和static静态成员属性是一样(在类外部使用”类名::常量”, 在类内部使用”self::常量”)
5. 常量一定要在声明时就给初值

PHP中常用的魔术方法

__call()
在调用对象中不存在的方法时就会出现系统报错,然后程序退出。在调用一个对象中不存在的的方法时自动调用该方法,通过设置__call()方法可以防止出现报错时程序崩溃并可设置输出的提示文本。因而可以通过__call()处理一些不存在方法的错误调用,不影响下面代码的执行。通过这一方法可变向实现其它语言如Java中的重载(Overload),即使用相同方法名,但通过传入不同数量参数以实现区分。
__toString()
直接输出对象引用时自动调用, 用来快速获取对象的字符串表示的最便捷的方式。
__clone()
克隆对使用clone来处理
原本 (原来的对象)
复本 (复制出来的对象)
__clone()是在克隆对象时自动调用的方法。只要一个对象一诞生,就要有初始化的动作( 和构造方法__construct作用相似),在__clone()方法中的$this关键字代表的是复本, $that代表原本对象。
__autoload()
其它的魔术方法都是在类中添加起作用, 这是一个唯一一个不在类中添加的方法。在页面中使用到一个类,只要用到类名就会自动将类名传给这个参数(__autoload($className))
对象串行化(序列化): 将一个对象转为二进制串 (对象是存储在内存中),通常使用情况有:
1. 将对象长时间存储在数据库或文件中时
2. 将对象在多个PHP文件中传输时
serialize() : 参数是一个对象, 返回来的就是串行化后的二进制串
unserialize() : 参数是对象的二进制串, 返回来的就是新生成的对象
__sleep()
是在序列化时自动调用的方法
作用:就是可以将一个对象部分串行化,只要这个方法中返回一个数组,数组中有几个成员属性就序列化几个成员属性,如果不加这个方法,则所有成员都会被序列化
__wakeup()
是在反序列化时自动调用的方法,也是对象重新诞生的一个过程(__construct(), __clone(),__wakeup())

抽象类、接口和多态

抽象类是一种特殊的类, 接口是一种特殊的抽象类, 而多态就要使用到抽象类或是接口
抽象类
抽象方法:如果一个类中的方法,没有方法体的方法就是抽象方法(即一个方法没有使用{}而直接使用分号结束),如果一个方法是抽象方法,就必须使用abstract修饰
abstract function test();  //抽象方法
function test(){
}//虽然方法体为空,但有方法体

什么是抽象类?
1. 如果一个类中,有一个方法是抽象的则这个类就是抽象类
2. 如果一个类是抽象类,则这个类也必须要使用abstract修饰
3. 抽象类是一种特殊的类,就是因为一个类中有抽象方法,其他不变。即可以在抽象类中声明成员属性,常量,非抽象的方法。
4. 抽象类不能实例化对象(不能通过抽象类去创建一个抽象类的对象)

要想使用抽象类,就必须使用一个类去继承抽象类,而且要想使用这个子类(也就是让子类可以创建对象),子类就必须不能再是抽象类。调用父类方法子类可以通过重写父类的方法(给抽象方法加上方法体)。
抽象方法中的方法没有方法体, 子类必须实现这个方法 (父类中没写具体的实现, 但子类必须有这个方法名),因抽象类是在定义一些规范,让子类按这些规范去实现自己的功能。

目的: 就是要将你自己写的程序模块加入到原来已经写好的程序中去 (设定好规范,有助于多程序员协同开发以及后续开发)

接口技术
接口中一种特殊的抽象类(抽象类又是一种特殊的类)。
接口和抽象类的作用是一样的,使用接口是因为在PHP是单继承的, 如果使用抽象类,子类实现完抽象类就不能再去继承其它的类了。如果既想实现一些规范, 又想继承或扩展一个其他类。就需要使用接口。

声明接口语法:
interface 接口名{
}

接口和抽象类的对比
1. 作用相同,都不能创建对象, 都需要子类去实现
2. 接口的声明和抽象类不一样
3. 接口被实现的方式和抽样类不一样
4. 接口中的所有方法必须是抽象方法,只能声明抽象方法(不用使用abstract修饰)
5. 接口中的成员属性只能声明常量,不能声明变量
6. 接口中的成员访问权限都必须是public, 抽象类中最低的权限是protected
7. 使用一个类去实现接口, 不是使用extends关键字, 而是使用implements这个词

(如果子类是重写父接口中抽象方法,则使用implements, 类实现接口, 抽象类实现接口使用implements 接口调用接口使用extends)
可以定义一个接口去继承另一个接口。可以使用抽象类去实现接口中的部分方法,如果想让子类可以创建对象,则必须重载接口中的全部抽象方法。
一个类可以去实现多个接口(按多个规范去开发子类), 使用逗号分隔多个接口名称;同时 一个类可以在继承一个类的同时去实现一个或多个接口(先继承,再实现 class Aa extends class Bb implements Cc,Dd,Ee)

使用implements的两个目的
1. 可以实现多个接口 ,而extends词只能继承一个父类
2. 没有使用extends词,可以去继承一个类, 所以两个可以同时使用

多态性

“多态”是面向对象设计的重要特性,它展现了动态绑定(dynamic binding)的功能,也称为“同名异式”(Polymorphism)。多态的功能可让软件在开发和维护时,达到充分的延伸性(extension)。事实上,多态最直接的定义就是让具有继承关系的不同类对象,可以对相同名称的成员函数调用,产生不同的反应效果。

退出移动版