第一章 面向对象思想的核心概念
面向对象是什么:面向对象(OOP)是一种程序设计范型,同事也是一张程序开发方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和可扩展性
面向过程、面向对象以及函数式编程呗称为编程语言中的三大范式(前两者同属于命令式编程)
类是对象的抽象组织,对象是类的具体存在
对象就是一堆数据,既然如此,可以把一个对象存储起来,以便需要时用。这就是对象的序列化。
序列化就是把保存在内存中的各个对象状态(属性)保存起来,并且在需要时可以还原出来
<?php
class student{
public $name='';
public $age='';
function say(){
echo '大家好';
}
}
$st=serialize(new student());
echo $st;
对象序列化后,存储的只是对象的属性。类是由属性和方法组成,而对象则是属性的结合,由同一个类生产的不同对象,拥有各自不同的属性,但共享了类的代码空间中方法区域的代码。
对象是什么?
对象在PHP中也是变量的一种,所以先看PHP源码对变量的定义:
zvalue_value 就是PHP底层的变量类型,zend_object_value obj就是变量中的一个结构,在PHP5中,对象在底层的实现是采取“属性数组+方法数组”来实现的。
对象在PHP是一种zend_object_value结构体来存储的。对象在ZEND(PHP底层引擎,类似于java的jvm)中定义如下:
ce是存储该对象的类结构,在对象初始化时保存了类的入口,相当于类指针的作用,prop erties是一个Hash Table,用来存放对象属性,guards用来阻止递归调用。类的标准方法在zend/zend_object_handlers.h文件中定义,具体实现则是在zend/zend_object_handlers.c文件中。
由源码可以知道,对象也是一种很普通的变量,不过是其携带了对象的属性和类的入口
对象和数组:
<?php
$student=array('name'=>'Tom','age'=>16);
$st=serialize($student);
var_dump($st);
对象和数组在内容上一模一样,区别在于:对象还有个指针,指向了它所属的类。在对student对象序列化的时候看到了student这个字符,就标志了对象归属于这个二类,可以立即执行对其执行所包含的方法。
总结:类是定义一系列属性和操作的模板,而对象则把属性进行具体化,然后交给类处理。
对象就是数据,对象本身不包含方法,但是对象有一个指针指向一个类,有对象必定有一个类何其对呀(但是有种特殊情况,就是标量进行强制类型转换的object,此时php一个称为"孤儿"的stdClass类就会收留这个对象)
PHP魔术方法:
它们是PHP中的内置方法,手册把这两个方法归到重载。
1>PHP和java区别:java重载指的一个类中可以定义参数列表不同但名字相同的多个方法,但是PHP只能在一个类中有一个构造方法。PHP的重载指动态创建类属性和方法。因此set和get归到重载里面,一定程度增强了程序的健壮性
2>实际上,toString方法也是一种序列化,PHP自带的serialize/unserialize也是进行序列化的,但是这组函数序列化时会产生一些无用信息,如属性字符串长度,造成存储空间的无谓浪费,因此可以实现自己的序列化和反序列化方法或者json_encode/json_decode也是个不错的选择,但是为什么echo一个对象就会报语法错误,原因就是echo 本来可以打印一个大型,而且实现了这个接口,但是PHP对其做了限制,只有实现toString后才允许使用,从下面的PHP源代码可以得到验证:
继承与多态
面向对象的优势在于类的复用。继承与多态都是对类进行复用一个是类级别的复用,一个是方法级别的复用。
组合与继承都是提高代码可重用性的手段,组合偏重整体和局部的关系,而继承偏重父与子的关系
从方法复用角度,如果两个类具有很多相同的代码和方法,可以从这两个类中抽象出一个父类,提供公共方法,然后这两个类作为子类提供个性方法。这时用继承更好
而组合就没有这么多限制。组合之间的类可以关系(体现为复用代码)很小,甚至于没有关系
两个如何抉择: 标准就是 低耦合(模块与模块之间尽可能独立存在,模块与模块之间的接口尽量少而简单)
按照这个思想,继承与组合两者都可以使用的情况下,更倾向于组合,因为:
1>继承破坏了封装性
例如鸟为父类,有羽毛和飞翔方法,子类天鹅和鸭子,显然鸭子不需要飞翔这个方法,但作为子类却可以无区别使用这个方法,破坏了类封装性。
2>继承是紧耦合的
使得父类和子类捆绑在一起。组合仅通过唯一接口和外部进行通信,耦合度低于继承
3>继承扩展负责
锁着继承层数增加和子类增加,设计大量方法重写。使用组合,可以根据类型约束,实现动态组合减少代码
4>和恰当继承可以能违反显示世界逻辑
比如:人作为父类,雇员、经理、学生为子类,存在这一问题,经理一定是雇员,学生也可能是雇员,而是用继承的话一个人无法拥有多个角色。而使用组合就可以较好解决这个问题
但是组合也有缺点,在创建组合对象时,组合需要一一创建局部对象,这一定程度增加了一些代码,而继承不需要,子类自动有父类方法,扩展简单
对于不是专门用于被继承的类,或者禁止被继承,也就是用final修饰符
总结:底层代码多用组合,顶层/业务层代码多用继承。前者可以提高效率,避免对象臃肿。后者可以提高灵活性,让业务使用更方便
多态:
弱语言的PHP里多态与传统强类型语言里面多态在实现和概念上有一些区别,总结:多态指同一类对象在运行时的具体化,PHP语言是弱类型的,实现多态更简单、更灵活,类型转换不是多态,PHP中子类和父类中,因为没有对象转型机制,把派生类对象复制给基类对象然后在调用函数时动态改变其执行,子类无法向上转型为父类,从而失去多态最典型的特征,多态的本质就是if...else,只不过实现的层级不同
class a{}
class b extends a{}
function do($obj){
$obj->方法();
}
do(new a());
do(new b());
判断传入对象所属的类不同调用其同名的方法
面向接口编程:
<?php
interface mobile{
public function run();
}
class plain implements mobile{
public function run(){
echo '我是飞机';
}
public function fly(){
echo '飞翔';
}
}
class car implements mobile{
public function run(){
echo '我是汽车';
}
}
class m{
function demo(mobile $a){
$a