OOP的好处 1.封装, 2继承, 3多态.
多态性是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息将可以产生不同的结果,这种现象称为多态性。
<?php // 定义了一个形状的接口,里面有两个抽象方法让子类去实现 interface Shape { function area(); function perimeter(); } // 定义了一个矩形子类实现了形状接口中的周长和面积 class Rect implements Shape { private $width; private $height; function __construct($width, $height) { $this->width = $width; $this->height = $height; } function area() { return "矩形的面积是:" . ($this->width * $this->height); } function perimeter() { return "矩形的周长是:" . (2 * ($this->width + $this->height)); } } // 定义了一个圆形子类实现了形状接口中的周长和面积 class Circular implements Shape { private $radius; function __construct($radius) { $this->radius=$radius; } function area() { return "圆形的面积是:" . (3.14 * $this->radius * $this->radius); } function perimeter() { return "圆形的周长是:" . (2 * 3.14 * $this->radius); } } // 把子类矩形对象赋给形状的一个引用 $shape = new Rect(5, 10); echo $shape->area() . "<br>"; echo $shape->perimeter() . "<br>"; // 把子类圆形对象赋给形状的一个引用 $shape = new Circular(10); echo $shape->area() . "<br>"; echo $shape->perimeter() . "<br>";
属性的五个作用域
public 都可以访问
private 只能在定义属性的类中访问
protect 继承链上访问
final 不能被子类覆盖
static
属性重载的处理
指php对当前不可访问对象的处理方式. 不可访问对象分为 不存在 和 访问权限受限两种. 注意 : 这里没有静态属性.
对于不存在对象, 用__set() 方法设置属性
<?php class Employee{ public $name; function __set($propName, $propValue){ $this->$propName = $propValue; } } $employee = new Employee(); $employee->name = '小明'; $employee->title = '工程师';
用__get()方法获取属性
<?php class Employee{ public $name; public $city; public $age; function __get($propName){ $vals = ['name', 'city']; if(in_array($propName, $vals)) return $this->propName; else return '不存在此属性'; } } $employee = new Employee(); $employee->name = '小明'; echo $employee->salary;
对于访问权限受限的对象 可以为私有属性创建两个方法 get() 和 set()
方法的作用域
public
private
protect
abstract 抽象方法, 只能在父类里面声明, 然后在子类中实现, 只有抽象类才能实现抽象方法
<?php abstract class Employee{ abstract function demote(); }
final 防止被子类覆盖, 如果覆盖将会报致命错误.
static
静态类成员 : 属性或方法被所有的类实例共享, 不能由特定的对象调用.
自动加载对象 __autoload()
定义一个特殊的函数__autoload(), 当脚本加载未定义的类时会自动调用该函数. 也可以使用spl_autoload_register — 注册__autoload()函数
高级特性
对象克隆 : 默认引用传递, 但使用克隆方法可以得到一个副本. 如果要调整对象的克隆行为, 可以使用__clone() 方法, 它会在克隆操作时自动调用.
继承 : 子类如果有构造函数, 则执行子类的构造函数, 否则执行父类的.
接口
定义了一种实现规范, 声明了必需的函数和常量, 但不给出具体实现. 原因是因为不同的实体可能有不同的实现方式
interface IniterfaceName{ CONST 1; ... CONST N; function memthodName1(); function memthodName2(); }
类通过使用implements实现接口, 如果没有实现全部方法, 则必须声明为抽象类. 可以通过实现多个接口来模拟多继承.
class Class_Name implements IniterfaceName{ function memthodName1(){ //具体实现 } function memthodName2(){ //具体实现 } }
抽象类
不能被实例化的类, 只能被其他类继承
命名空间
不支持 : 方法重载, 操作符重载, 多继承,
方法的重写和重载
父类中存在某个方法, 子类中又重新定义了重名方法, 称为重写. 并没有更改类的结构
<?php class father{ public function test(){ echo "father"; } } class son extends father{ public function test(){ parent::test();//还想要这父类的东西 echo "son "; } } $son = new son(); $son->test();
重载 : 传入不同的参数, 根据参数值返回不同的结果. php本身不支持, 下面代码会报错
<?php class A{ public function test(){ echo "test1"; } public function test($a){ echo "test2"; } } $a=new A(); $a->test(); $a->test($a);
我们可以通过__call()来模拟重载操作. 注意, 这里为非静态调用, 静态调用使用__callstatic().
<?php class Magic { function __call($name,$arguments) { if($name=='foo') { if(is_int($arguments[0])) $this->foo_for_int($arguments[0]); if(is_string($arguments[0])) $this->foo_for_string($arguments[0]); } } private function foo_for_int($x) { echo "oh an int!"; } private function foo_for_string($x) { echo "oh a string!"; } } $x = new Magic(); $x->foo(3); $x->foo("3"
使用final关键字标记的类不能被继承, 只能被实现, 使用final标记的方法不能被子类覆盖, 是最终版本.
对象在内存中的体现:
内存大体分为4段, 栈空段, 堆空段, 代码段, 初始化静态段. 栈内存是可以直接存取的,而堆内存是不 可以直接存取的内存, 我们的对象来说就是一种大的数据类型而且是占用空间不定长的类型,所以说对象是放在堆里面的,但对象名称是放在栈里面的,这样通 过对象名称就可以使用对象了
从上图可以看出 $p1 = new Person();等号右边是真正的对象实例, 在堆内存里面的实体,上图一共有3次new Person(),所以会在堆里面开辟3个空间,产生3个实例对象,每个对象之间都是相互独立的,使用自己的空间,在PHP里面,只要有一个new这个关键字出现就会实例化出来一个对象,在堆里面开辟一块自己的空间
常见魔术方法
__construct();
__destruct(); 注意 : php对象体现在堆栈中, 所以这里是先进后出.
__isset(); 检查属性是否存在, 专门为私有属性设置(private, protect), public属性不走__set().
__unset(); 销毁属性, 其它同上.
__toString() : 在直接输出对象时调用, 必须return 一个字符串
__clone(): 克隆对象时调用.
__call() : 处理调用错误. 这个方法有2个参数,第一个参数为调用不存在的方法过程中,自动调用__call()方法时,把这个不存在的方法的方法名传给第一个参数, 第二个参数传递一个参数数组.
__sleep(): 在序列化时自动调用, 不接受任何参数, 但返回一个数组,其中包含需要串行化的属性。末被包含的属性将在串行化时被忽略,如果没有__sleep()方法,PHP将保存所有属性。
__wakeup() : 反序列化时调用
后期静态绑定, static:: 不再是当前方法所在的类, 而是运行时所在的类. 如果改成self::who() 则输出为A
<?php class A { public static function who() { echo __CLASS__; } public static function test() { static::who(); // 后期静态绑定从这里开始 } } class B extends A { public static function who() { echo __CLASS__; } } B::test()