二、面向对象主要特征
1. 构造方法与析构方法
1) 构造方法(__construct)
用于类的初始化,当一个类被初始化时,首先进入的就是类的构造方法,用户初始化一些类的操作
2.析构方法(__destruct)
当一个类的实例被注销时,会调用析构方法,这个方法不是特别常用,但是代表的是一类的实例生命周期的终结.
class Computer
{
public function __construct()
{
echo '构造方法:初始化' . PHP_EOL;
}
public function game()
{
echo '玩游戏' . PHP_EOL;
}
public function __destruct()
{
echo '析构方法:注销操作' . PHP_EOL;
}
}
$computer = new Computer();
$computer->game();
// 输出结果:
构造方法:初始化
玩游戏
析构方法:注销操作
上面代码执行结果,体验了一个类从被实例到被注销的过程
当一个 PHP 执行脚本被执行完,其所有类的实例都会被注销,所有都会走 __destruct 函数,下面是一个复杂的例子,在类的实例化时,在构造函数中传入某个私有属性的初始化值,并在后续的函数调用中提现私有属性的意义,最后我们可以看到,两个类的实例在 PHP 脚本执行结束后都被注销.
class Computer
{
private $memery = 0;
public function __construct($memery = 0)
{
echo '构造方法:初始化' . PHP_EOL;
$this->memery = $memery;
}
public function game()
{
if ($this->memery >= 1024) {
echo '大内存电脑, 可以玩游戏' . PHP_EOL;
} else {
echo '小内存电脑,不能玩游戏';
}
echo '玩游戏' . PHP_EOL;
}
public function __destruct()
{
echo '析构方法:注销操作' . PHP_EOL;
}
}
$computer1 = new Computer(1024);
$computer1->game();
$computer2 = new Computer(2048);
$computer2->game();
// 输出结果:
构造方法:初始化
大内存电脑, 可以玩游戏
玩游戏
构造方法:初始化
大内存电脑, 可以玩游戏
玩游戏
析构方法:注销操作
析构方法:注销操作
2. 类的继承与 final 关键字
类的继承关系类似父子关系, 子类继承父类,拥有父类的属性与方法(public 和 protected)
1) 类的继承简介
类的继承好处
- 扩展性
// 定义父类: Vehicle类
class Vehicle
{
public function getName()
{
echo '交通工具' . PHP_EOL;
}
}
// 定义子类: Bug 类
class Bus extends Vehicle
{ }
$bus = new Bus();
$bus->getName();
// 输出结果: 交通工具
3) 不同修饰符下属性与方法影响类的继承
上面提到,(public, protected) 修饰的类的属性与方法才能够被子类继承.如果是 private 属性,子类是没有办法继承的
// 定义父类: Vehicle类
class Vehicle
{
protected function name()
{
echo '交通工具' . PHP_EOL;
}
// 定义私有方法
private function author()
{
echo 'zZ爱吃菜' . PHP_EOL;
}
}
// 定义子类: Bug 类
class Bus extends Vehicle
{
public function getName()
{
$this->name();
}
public function getAuthor()
{
$this->author();
}
}
$bus = new Bus();
// protected 方法可以被子类继承
$bus->getName();
// 输出结果: 交通工具
// protected 方法无法被外部调用
$bus->name();
// 输出结果: protected 修复的方法不能被外部使用,但可以被子类继承内部使用.
PHP Fatal error: Uncaught Error: Call to protected method Vehicle::name() from context ''
// private 方法无法被子类继承
$bus->getAuthor();
// 输出结果:
Fatal error: Uncaught Error: Call to private method Vehicle::author() from context 'Bus'
3) 类的属性与方法重写
子类可以覆盖父类方法和属性
// 定义父类: Vehicle类
class Vehicle
{
public function speed()
{
echo '5km/h' . PHP_EOL;
}
}
// 定义子类: Bug 类
class Bus extends Vehicle
{
// 重写父类方法 speed
public function speed()
{
echo '80km/h' . PHP_EOL;
}
}
$bus = new Bus();
$bus->speed();
输出结果: 80km/h
4) 子类实例化过程中
我们知道,类的初始化时会调用构造方法,如果子类初始化时会如何调用构造方法呢?
- 如果父类定义了构造方法,而子类没有,则调用父类的构造方法
- 如果父类子类都定义了构造方法,子类重写父类构造方法
- 子类可以手动调用父类构造方法
// 定义父类: Vehicle类
class Vehicle
{
public function __construct()
{
echo '初始化 Vehicle' . PHP_EOL;
}
}
// 定义子类: Bug 类
class Bus extends Vehicle
{
public function __construct()
{
parent::__construct();
echo '初始化 Bus' . PHP_EOL;
}
}
$bus = new Bus();
// 输出结果:
初始化 Vehicle
初始化 Bus
注意: 一般我们约定类的集成不超过三级,因为继承层数太多,会导致代码难以维护.
5) final 关键字
final 只能修饰 类(class) 和 类的方法(function)
- final 修饰 class : 表示 这个类不能被继承
- final 修复 类的方法: 表示这个类的方法不能被重写
// 定义父类: Vehicle类
final class Vehicle
{
public function __construct()
{
echo '初始化 Vehicle' . PHP_EOL;
}
}
// 定义子类: Bug 类
class Bus extends Vehicle
{}
$bus = new Bus();
// 输出结果: 表示 final class (Vehicle) 不能被继承
PHP Fatal error: Class Bus may not inherit from final class (Vehicle)
3. 静态绑定
// 定义父类: Vehicle类
class Vehicle
{
public static function name()
{
echo 'Vehicle 的 name 方法' . PHP_EOL;
}
public static function getName()
{
self::name();
}
}
// 定义子类: Bug 类
class Bus extends Vehicle
{
public static function name()
{
echo 'Bus 的 name 方法' . PHP_EOL;
}
}
Bus::getName();
// 输出结果:
Vehicle 的 name 方法
查看上面的代码,我们发现,静态方法 name() Vehicle 与 Bus 都有,但是在调用 Bus::getName();
时却执行的是 Vehicle 方法.
那么问题来了: 如果我们希望的是 getName() 方法调用的是 Bus 的方法呢?
static 关键字
通过 static 关键字, static::name()
此时 static 就代表调用 who 方法的当前类.也就是后期绑定的概念.
// 定义父类: Vehicle类
class Vehicle
{
public static function name()
{
echo 'Vehicle 的 name 方法' . PHP_EOL;
}
public static function getName()
{
static::name();
}
}
// 定义子类: Bug 类
class Bus extends Vehicle
{
public static function name()
{
echo 'Bus 的 name 方法' . PHP_EOL;
}
}
Bus::getName();
// 输出结果:
Bus 的 name 方法