PHP面向对象02:面向对象高级

一、设计模式

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. 重写

  • 子类可以重写父类的任意类成员,用于扩展或更改某些业务逻辑。
  • 重写的要求:
    1. 重写的子类成员权限范围必须比父类更开放。
    2. 子类方法必须与父类重写方法参数一致。
    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
$man->show();  // ManHelloWorld
  • 如果想用父类的被重写的方法,需要在子类中使用 parent 关键字
  • parent 只能访问方法和静态属性,不能访问成员属性(被重写的属性直接没了)。
class Human{
    public function show(){
        echo __CLASS__;
    }
}

class Man extends Human {
    public function show() {
        parent::show();
        echo __CLASS__ . "HelloWorld";
    }
}

4. PHP继承特点

  1. PHP只能单继承。如果想要继承多个类,使用链式继承。
  2. 继承只有私有方法不能被继承。
  3. 允许子类继承父类的构造方法和析构方法。

5. 静态延迟绑定

  • self是一种静态绑定,不管是子类还是父类,self写在哪个类里就代表哪个类。
  • 静态延迟绑定使用关键字 static,即当方法被访问时,哪个类访问就绑定那个类。
  • 静态延迟绑定需要使用到静态成员的重写。
<?php
class Human{
    public static $name = 'Human';

    public static function getName() {
    	// 静态绑定
        echo self::$name."<br>";   // Man访问,依旧输出Human的name
        // 静态延迟绑定
        echo static::$name . "<br>";  // Man访问,输出Man里面的name
    }
}
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{
    // 引入trait公共代码
    use Eat;
}
// 可以直接使用
$man = new Man();
$man->showtime();

2. 同时使用多个 trait

  • 一个类可以使用多个 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方法
        Eat::show insteadof Sleep;
        // Sleep的show方法改名为shows
        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;
    }
}

七、对象遍历

  • 遍历对象是指将对象中所有公有属性以键值对的形式取出并进行访问。
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iFulling

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值