思考PHP语言二:面向对象
【概述】
PHP是一门支持面向过程,也支持面向对象的动态语言。从PHP5开始,PHP对于面向对象的支持好了很多。
面向对象程序设计是抽象数据类型的抽象原理的一种应用。当我们使用类时,我们应该了解这是一种抽象数据类型,对象是属于所对应类的类型的。
面向对象的三个特征:封装,继承,多态。这三个特征也可以用:抽象数据类型,继承和方法调用与方法间的动态绑定来说明。抽象是我们与程序复杂性抗争的一种方式,通过这种方式,我们可以关注并且仅关注主要的属性而忽略次要的属性。从语法的角度来说,抽象数据类型是一种封装,它不仅仅包括对于数据的封装,也包括其提供方法的封装。通过访问控制,从而实现数据或方法的隐藏和暴露,这就是我们经常所说的类,它的实例我们称之为对象。
【PHP的抽象数据类型】
PHP以类的形式实现封装,类中所定义的数据称为成员变量;而类中所定义的函数称为成员函数或成员方法。成员函数和成员变量又分别有类属性和实例属性。
类属性的成员函数和成员变量
PHP中的类属性成员都以静态的方式存在,为所有的实例共享(包括成员函数和成员变量),可以通过类名直接调用。但是其仅在一个PHP的生命周期内有效,这与java等有较大的差别。
实例属性的成员函数和成员变量
对于实例属性的成员函数和成员变量,一个类的所有实例共享一套成员函数,而每个实例都有属于自己的一套成员变量,这也是我们在做面向对象的程序结构设计时将数据尽量向下移,将共用的方法尽量向上移的原因。
信息隐藏
PHP中的信息隐藏通过访问控制实现,对于需要隐藏的数据将其以私有成员定义,在其声明前添加private关键字,对于需要公开的数据将其以公有成员定义,在其定义前添加public关键字,也可以不加任何关键字,因为PHP默认情况下是public。PHP的私有和公有访问权限与java相同,
命名封装
在构建大型系统时,为解决不同团队对于函数或类等的命名冲突,我们需要引入命名封装,命名封装是一些逻辑上的封装。在PHP中使用命名空间实现,只是这在PHP5.3版本后才有相关支持。
在PHP中,类,函数和常量这三种类型受命名空间的影响,命名空间通过关键字namespace 来声明,对于层次化的命名空间以反斜杠隔开,如:namespace com\toll\level;
【PHP的继承】
继承是软件复用的一种形式,它不仅可以让程序人员以一个已有类为基础,设计一个修改了的后代类型,还可以定义相关的程序结构和关系。这种结构和关系在一定程度上反映了这些实体的上下代关系。从这里就产生了父类,子类等概念,并且在访问控制中也产生了protected,使用protected时,它的最大访问范围为其派生类。在子类中我们可以定义新的成员变量和新的成员函数,并且可以重载父类的成员函数,但是无法重载父类的构造函数,如果在实例化时需要调用父类的构造函数,我们需要手动调用父类的构造函数,PHP本身不会自动调用。
另外,关于PHP的构造函数的一个历史遗留问题:以类名为构造函数和以__construct为构造函数,在之前写过一篇文章介绍二者在调用时的选择方式。PHP源码阅读笔记二十七:PHP对构造方法的识别
PHP没有多继承,只支持单继承,但是他拥有接口,它提供了一种多继承的方式。这点和java一样。
接口的定义与类的定义类似,只是关键字变成了interface,接口可以包含常量和方法声明。它的作用仅仅是定义类的说明。类可以实现多个接口,但是类也必须实现接口中的所有方法。接口可以模拟实现多继承,也提供了另一种形式的多态,但是这对于PHP来说没有多大的意义,因为PHP的变量本身就是多态的。
继承是作为增加复用可能性的一种手段,但是它在继承层次中产生的类之间的相互依赖性,产生了一些强耦合。而这与之前的封装的优点刚好相反,封装就是为了保持类之间的相互独立性。所以在作设计时,我们如果使用继承就需要考虑是否真的需要,是否真的是is-a的关系。更多的时候我们会选择使用委托来实现。
【PHP的动态绑定】
PHP本身就是动态绑定的。