PHP面向对象02:面向对象高级
- 一、设计模式
-
- 二、面向对象三大特性
-
- 三、继承
- 1. 实现继承
- 2. 有限继承
- a. 属性都能继承
- b. 公有方法
- c. 受保护的方法
- d. 静态成员
- 3. 重写
- 4. PHP继承特点
- 5. 静态延迟绑定
- 6. 最终类和最终方法
- 7. 抽象类和抽象方法
- 四、接口
- 五、代码复用
- 1. trait 基本使用
- 2. 同时使用多个 trait
- 3. trait 其他用法
- 六、PHP重载
-
- 七、对象遍历
一、设计模式
1. 单例模式
- 单例模式:一个类最多只有一个对象。
- 单例模式的目的时为了保护资源的唯一性。
- 设计规范:三私一公。
class Singleton{
private static $obj = null;
private function __construct() {
}
private function __clone() {
}
public static function getInstance() {
if (!(self::$obj instanceof self)) {
self::$obj = new self();
}
return self::$obj;
}
}
2. 工厂模式
- 工厂模式是一种按需生产对象的模式。
- 优点:方便后期对类的维护。
- 缺点:随着功能增加,需要开发多个工厂。
<?php
class Man{
public function display() {
echo "这是男人";
}
}
class Woman{
public function display() {
echo "这是女人";
}
}
class HumanFactory{
public static function getInstance($classname) {
switch ($classname) {
case 'w':
return new Woman();
case 'm':
return new Man();
default:
return null;
}
}
}
$woman = HumanFactory::getInstance('w');
$man = HumanFactory::getInstance('m');
$woman->display();
$man->display();
二、面向对象三大特性
1. 封装
- 封装是指将数据和对数据的操作捆绑在一起,形成对外界隐蔽,同时对外提供可以操作的接口(通常是方法)。
- 封装是从对象抽象成类的过程。
2. 继承
- 继承的基础:子类与父类之间本身是一种包含的关系。
- 继承关键字:
extends
。 - 继承效果:子类可以直接访问父类中已经存在的公共
public
成员。
3. 多态
- 在继承的前提下,同时出现方法的重写。父类指向子类的属性。
- PHP中不支持多态。
三、继承
1. 实现继承
- 继承关系利用extends关键字实现。
- 实现继承关系后,子类对象可以访问父类被继承的成员。而父类对象不可以访问子类成员。
<?php
class Human {
public function eat() {
echo "eat";
}
}
class Man extends Human {
}
$man = new Man();
$man->eat();
2. 有限继承
- 继承内容:公有成员、受保护成员、私有属性(所有属性和除私有方法以外的方法)。
- 不能继承:私有方法。
- protected 只能在子类内部访问,不能再外部访问。
a. 属性都能继承
b. 公有方法
c. 受保护的方法
外部访问不了,只能在类内部访问
d. 静态成员
3. 重写
- 子类可以重写父类的任意类成员,用于扩展或更改某些业务逻辑。
- 重写的要求:
- 重写的子类成员权限范围必须比父类更开放。
- 子类方法必须与父类重写方法参数一致。
- 父类私有方法不会被继承,所以不会被重写。
<?php
class Human{
public $name = "Human";
public function show(){
echo __CLASS__;
}
}
class Man extends Human {
public $name = "Man";
public function show() {
echo __CLASS__ . "HelloWorld";
}
}
$man = new Man();
echo $man->name;
$man->show();
- 如果想用父类的被重写的方法,需要在子类中使用
parent
关键字 parent
只能访问方法和静态属性,不能访问成员属性(被重写的属性直接没了)。
class Human{
public function show(){
echo __CLASS__;
}
}
class Man extends Human {
public function show() {
parent::show();
echo __CLASS__ . "HelloWorld";
}
}
4. PHP继承特点
- PHP只能单继承。如果想要继承多个类,使用链式继承。
- 继承只有私有方法不能被继承。
- 允许子类继承父类的构造方法和析构方法。
5. 静态延迟绑定
- self是一种静态绑定,不管是子类还是父类,self写在哪个类里就代表哪个类。
- 静态延迟绑定使用关键字
static
,即当方法被访问时,哪个类访问就绑定那个类。 - 静态延迟绑定需要使用到静态成员的重写。
<?php
class Human{
public static $name = 'Human';
public static function getName() {
echo self::$name."<br>";
echo static::$name . "<br>";
}
}
class Man extends Human{
public static $name = 'Man';
}
Man::getName();
6. 最终类和最终方法
- 都使用
final
关键字修饰。 - 最终类,表示此类不可以被继承。
- 最终方法,表示该方法不可以被重写。
<?php
class Man{
final public function getName(){
echo __CLASS__;
}
}
final class Boy extends Man{}
7. 抽象类和抽象方法
- 都使用
abstract
关键字修饰。 - 抽象类,表示不能被实例化,只能被继承。目的是规范某些类必须有某些方法。
- 抽象方法,表示该方法不能有方法体,而且抽象方法的类必须声明为抽象类。
- 抽象方法本身就是需要被重写的,所以不能私有。
<?php
abstract class Human{
abstract public function eat();
public function drink(){
echo "喝水";
}
}
class Man extends Human{
public function eat() {}
}
四、接口
- 接口,使用
interface
关键字定义,用来规范一些共性类必须实现的方法。 - 接口不是类,不可以被实例化,只能被类实现。
- 接口中只能定义公有抽象方法(在接口中的方法默认是抽象方法)和接口常量。
- 类实现接口时,必须实现接口中所有的抽象方法。
<?php
interface Human {
const NAME = "人";
public function eat();
}
class Man implements Human{
public function eat() {}
}
interface Human {}
interface Animal{}
interface Dog extends Animal{}
interface Ape extends Human,Animal{}
interface Human {
const NAME = "人";
public function eat();
}
abstract class Woman implements Human {
abstract public function drink();
}
class Girl extends Woman {
public function eat() {
echo "吃饭";
}
public function drink() {
echo "喝水";
}
}
五、代码复用
1. trait 基本使用
trait
是为PHP准备的一种代码复用机制,类似于class
。trait
内部可以拥有成员属性、成员方法、静态成员,但不能有常量。trait
不是类,不能被实例化。trait
是用来将公共代码提供给其他类使用的,类使用trait
的前提是加载对应的trait
。
<?php
trait Eat{
public $time = 100;
public function showtime(){
echo $this->time;
}
}
class Man{
use Eat;
}
$man = new Man();
$man->showtime();
2. 同时使用多个 trait
<?php
trait Eat{
...
}
trait Sleep{
...
}
class Man{
use Eat, Sleep;
}
- 多个
trait
有同名方法,处理冲突的方法是 insteadof 代理处理和对被替换方法使用别名。
<?php
trait Eat{
public function show(){
echo "吃饭";
}
}
trait Sleep{
public function show(){
echo "睡觉";
}
}
class Man{
use Eat, Sleep{
Eat::show insteadof Sleep;
Sleep::show as shows;
}
}
$man = new Man();
$man->show();
$man->shows();
- 类中不允许定义与
trait
中同名的属性,但方法可以(类方法覆盖trait方法)。 - 如果
trait
与父类中有同名方法, trait
方法将覆盖父类同名方法。如果要访问父类方法,可以使用 parent
关键字。 - 优先级:自己的方法 > trait 方法 > 父类方法。
<?php
trait Eat{
public function show(){
echo "吃饭";
}
}
class Human{
public function show(){
echo "人";
}
}
class Woman extends Human{
use Eat;
}
$woman = new Woman();
$woman->show();
3. trait 其他用法
trait
不能自己访问,只能用来给其他代码提供代码复用。- 允许类在使用
trait
时,使用更高的访问控制权。
trait Drink{
private function show(){
echo "喝水";
}
}
class Girl{
use Drink{
show as public eshow;
}
}
$girl = new Girl();
$girl->eshow();
trait
可以使用抽象方法,用来规范使用类必须实现对应抽象方法。使用类要么是抽象类,要么必须实现抽象方法。
六、PHP重载
- 是指当某些不允许的操作发生时,会自动调用的一种内部机制,即自动调用相关的魔术方法。
- 魔术方法:系统为类预先设计好的,只需要开发者实现的方法。魔术方法以
__
开始。构造方法、析构方法、克隆方法都是魔术方法。 - 重载目的:不让程序允许出错,在类内部由我们自己控制内容的访问。
1. 属性重载
- 当PHP对象访问不存在或没有权限访问的属性时自动调用的方法。
方法名 | 说明 |
---|
__get($key) | 读属性时触发 |
__set($key, $value) | 写属性时触发 |
__isset($key) | 外部调用isset函数或empty函数时触发 |
__unset($key) | 外部调用unset函数删除对象属性时触发 |
__toString() | 对象被当成普通变量输出或连接时触发 |
<?php
class Human{
private $age = 10;
public function __get($name) {
echo $name . '----' . __METHOD__;
$allow = array('age');
if (in_array($name, $allow)) {
return $this->$name;
}
return false;
}
public function __set($name, $value) {
echo $name . ":" . $value . "----" . __METHOD__;
}
public function __isset($name) {
echo $name . '----' . __METHOD__;
}
public function __unset($name) {
echo $name . '----' . __METHOD__;
}
public function __toString() {
echo '----' . __METHOD__;
return "123";
}
}
2. 方法重载
- 当PHP对象访问不存在或没有权限访问的方法时自动调用的方法。
方法名 | 说明 |
---|
__call($function_name[,$args]) | 对象调用不可调用方法时触发 |
__callStatic($function_name[,$args]) | 类访问不可调用静态方法时触发 |
class Man {
private function show() {}
private static function show2() {}
public function __call($name, $arguments) {
$allow = array('show');
if (in_array($name, $allow)) return $this->$name($arguments);
return false;
}
public static function __callStatic($name, $arguments) {
return false;
}
}
七、对象遍历
- 遍历对象是指将对象中所有公有属性以键值对的形式取出并进行访问。