加密白客养成计划(PHP面向对象,类,构建)

56 阅读5分钟

今日目标

1.2 面向对象介绍

1.2.1 介绍

面向对象就是把程序里的东西都当成 "东西" 来看。就像现实中你看到的一切 —— 猫、手机、汽车,每个 "东西" 都有自己的特点(比如猫有颜色、有品种)和能做的事(比如猫会叫、会跑)。

以前的编程可能更像列清单:第一步做什么,第二步做什么。而面向对象更像在描述一个小世界,里面有各种 "东西",它们之间互相配合。

1.2.2 面向对象的好处

  • 省事:写一次代码,多个地方能用,不用重复劳动
  • 好改:改一个地方,不影响其他地方,不会牵一发而动全身
  • 好懂:结构清晰,就像现实世界的东西一样,容易理解
  • 能长大:项目从小做大时,代码不会乱成一团麻
  • 多人合作方便:你负责写 "汽车",我负责写 "道路",互不干扰

1.3 类和对象

  • :就是 "类别",比如 "狗" 就是一个类,它描述了所有狗都有的特点(有毛、有尾巴)和技能(会叫、会跑)
  • 对象:就是具体的某个东西,比如你家那只叫 "旺财" 的金毛,就是 "狗" 这个类的一个对象

举个例子:"水果" 是类,你手里拿的那个苹果就是对象

1.4 在PHP中实现类和对象

1.4.1 创建类

在 PHP 里,用class关键字来定义一个类,就像写一份 "说明书"

<?php
// 定义一个"狗"类(写一份狗的说明书)
class Dog {
    // 狗的特征(属性)
    public $name;  // 名字
    public $color; // 颜色
    
    // 狗的技能(方法)
    public function bark() {
        // 输出"名字叫的汪汪叫"
        echo $this->name . "在汪汪叫";
    }
}
?>

1.4.2 对象实例化

有了说明书,就能造个具体的狗了,用new关键字:

<?php
// 用Dog类造一只具体的狗
$wangcai = new Dog();
​
// 给这只狗起名字、定颜色
$wangcai->name = "旺财";  // ->就像"的",$wangcai->name就是"旺财的名字"
$wangcai->color = "黄色";
​
// 让这只狗叫一声
$wangcai->bark();  // 输出:旺财在汪汪叫// 再造一只狗
$dahuang = new Dog();
$dahuang->name = "大黄";
?>

1.4.3 对象的比较

比较两个对象有两种方式,很好理解:

var_dump 可以用来比较对象是不是一样的 一样的就输出true

<?php
$dog1 = new Dog();
$dog1->name = "小白";
$dog1->color = "白色";
​
$dog2 = new Dog();
$dog2->name = "小白";
$dog2->color = "白色";
​
$dog3 = $dog1;  // 让dog3和dog1是同一只狗
​
// 比较两只狗是不是长得一模一样
var_dump($dog1 == $dog2);  // 结果:true(长得一样)
​
// 比较是不是同一只狗
var_dump($dog1 === $dog2);  // 结果:false(不是同一只)
var_dump($dog1 === $dog3);  // 结果:true(是同一只)
?>

1.5 属性

属性就是对象的 "特征"。比如手机的属性有:品牌、颜色、内存大小;人的属性有:姓名、年龄、身高

<?php
class Phone {
    // 手机的属性
    public $brand;   // 品牌
    public $color;   // 颜色
    public $storage; // 存储容量
}
​
// 造一个手机对象
$myPhone = new Phone();
$myPhone->brand = "华为";
$myPhone->color = "蓝色";
$myPhone->storage = "512G";
​
// 看看我的手机是什么样的
echo "我的手机是{$myPhone->color}{$myPhone->brand},有{$myPhone->storage}内存";
?>

1.6 方法

方法就是对象能 "做什么"。比如手机能打电话、发微信;汽车能开、能停

<?php
class RemoteControl {
    // 遥控器能开电视
    public function turnOn() {
        echo "电视打开了";
    }
    
    // 遥控器能关电视
    public function turnOff() {
        echo "电视关闭了";
    }
    
    // 遥控器能换台
    public function changeChannel($channel) {
        echo "换到{$channel}频道";
    }
}
​
// 拿起遥控器
$tvRemote = new RemoteControl();
​
// 开电视
$tvRemote->turnOn();  // 输出:电视打开了// 换台到5频道
$tvRemote->changeChannel(5);  // 输出:换到5频道// 关电视
$tvRemote->turnOff();  // 输出:电视关闭了
?>

1.7 访问修饰符

就是控制哪些属性和方法能被外面访问,就像:

  • public(公共的) :像商店橱窗里的商品,谁都能看能摸
  • protected(受保护的) :像家里的客厅,自己家人能进,外人不能
  • private(私有的) :像自己的日记本,只有自己能看
  • <?php
    class Person {
        public $name;    // 名字(公开的,谁都能知道)
        protected $age;  // 年龄(自己和家人知道就行)
        private $salary; // 工资(只有自己知道)
        
        // 设置年龄(提供一个方法让外面能设置,但自己可以控制)
        public function setAge($age) {
            // 年龄不能瞎填
            if ($age > 0 && $age < 150) {
                $this->age = $age;
            }
        }
        
        // 获取年龄
        public function getAge() {
            return $this->age;
        }
    }
    ​
    $xiaoli = new Person();
    $xiaoli->name = "小李";  // 可以直接设置名字
    $xiaoli->setAge(28);     // 通过方法设置年龄echo $xiaoli->name;      // 可以直接看名字
    echo $xiaoli->getAge();  // 通过方法看年龄
    // echo $xiaoli->age;    // 不行!不能直接看受保护的属性
    ?>
    

1.8 类和对象在内存中的分布

简单想象一下:

  • 类就像一本菜谱,放在书架上(内存的某个地方),只需要一本
  • 每个对象就像根据菜谱做出来的菜,放在盘子里(内存的另一个地方)
  • 所有的菜都照着同一本菜谱做(共享类的方法),但味道可能略有不同(各自的属性值)

比如,"宫保鸡丁" 这个类是菜谱,你做的宫保鸡丁和饭店做的宫保鸡丁是两个对象,做法一样(方法相同),但辣度可能不同(属性值不同)。

1.9 封装

就是 "该露的露,该藏的藏"。就像电视机,我们只需要按遥控器(露出来的部分),不需要知道里面的电路板怎么工作(藏起来的部分)

<?php
class BankCard {
    // 卡号可以让人看,但余额和密码要藏起来
    public $cardNumber;
    private $balance;
    private $password;
    
    // 构造方法:办卡时设置卡号和密码
    public function __construct($cardNumber, $password) {
        $this->cardNumber = $cardNumber;
        $this->password = $password;
        $this->balance = 0;  // 新卡余额为0
    }
    
    // 存钱(公开方法)
    public function deposit($money) {
        $this->balance += $money;
        echo "存了{$money}元,现在余额{$this->balance}元";
    }
    
    // 取钱(需要密码)
    public function withdraw($money, $inputPwd) {
        if ($inputPwd != $this->password) {
            echo "密码错误";
            return;
        }
        
        if ($money > $this->balance) {
            echo "余额不足";
            return;
        }
        
        $this->balance -= $money;
        echo "取了{$money}元,现在余额{$this->balance}元";
    }
}
​
// 办一张卡
$myCard = new BankCard("622848123456789", "888888");
​
// 存点钱
$myCard->deposit(1000);
​
// 取点钱
$myCard->withdraw(300, "888888");
​
// 别人能看到卡号,但看不到余额和密码
echo "卡号是:{$myCard->cardNumber}";
?>

1.10 构造方法

构造方法就是 "刚创建对象时自动执行的方法"。就像你买了新手机,第一次开机时会自动让你设置语言、连接 WiFi—— 这些就是手机的 "构造方法" 在工作。

在 PHP 里,构造方法叫__construct()(两个下划线,别写错了)

1.10.1 介绍

1.10.2 构造函数作用:初始化成员变量

<?php
class Student {
    public $name;
    public $studentId;
    public $className;
    
    // 构造方法:创建学生对象时自动调用
    public function __construct($name, $studentId, $className) {
        $this->name = $name;
        $this->studentId = $studentId;
        $this->className = $className;
        echo "新学生{$name}加入{$className}班";
    }
}
​
// 创建学生对象时,直接传参数给构造方法
$stu = new Student("张三", "2023001", "高三一班");
​
// 不用再手动设置属性了
echo $stu->name;  // 输出:张三
echo $stu->className;  // 输出:高三一班
?>

1.11 析构方法

析构方法和构造方法相反,是 "对象要消失时自动执行的方法"。就像你离开家时,会自动关灯、锁门 —— 这些就是 "析构方法" 在工作

PHP 里析构方法叫__destruct()(也是两个下划线)。

<?php
class Lamp {
    private $isOn = false;
    
    // 开灯(构造方法)
    public function __construct() {
        $this->isOn = true;
        echo "灯开了";
    }
    
    // 关灯(析构方法)
    public function __destruct() {
        $this->isOn = false;
        echo "灯关了";
    }
}
​
// 开灯
$lamp = new Lamp();  // 输出:灯开了// 使用灯...// 当灯不再使用时,自动关灯
// 脚本结束时,会看到输出:灯关了
?>

1.11.1 介绍

1.11.2 计算机的内存管理

简单说,计算机内存就像你家的衣柜:

  • 当你创建对象时,就像把衣服放进衣柜(分配内存)
  • 当这件衣服你不再穿了,就要把它扔掉,腾出空间(释放内存)
  • 析构方法就像扔衣服前,先把口袋里的东西掏出来(释放资源)

1.11.3 思考题

  1. 析构方法什么时候执行?

    • 一般是在对象用不上的时候,或者程序结束的时候,由系统自动安排。
  2. 如果打开文件后不关闭会怎么样?

    • 系统能同时打开的文件数量有限,一直不关闭可能导致无法再打开新文件
    • 就像你打开了很多书,不合上,桌子就摆满了,没法再放新书了

1.12 继承

1.12.1 继承介绍

继承就是 "子承父业"。子类可以继承父类的所有本领,还能自己学新本领。就像儿子会继承父亲的一些技能,还能学会父亲不会的新技能。

PHP 用extends关键字实现继承:

<?php
// 父类:动物
class Animal {
    protected $name;
    
    public function __construct($name) {
        $this->name = $name;
    }
    
    // 所有动物都会吃
    public function eat() {
        echo "{$this->name}在吃东西";
    }
}
​
// 子类:鸟(继承自动物)
class Bird extends Animal {
    // 鸟还会飞
    public function fly() {
        echo "{$this->name}在天上飞";
    }
}
​
// 子类:鱼(继承自动物)
class Fish extends Animal {
    // 鱼还会游
    public function swim() {
        echo "{$this->name}在水里游";
    }
}
​
// 造一只鸟
$bird = new Bird("麻雀");
$bird->eat();  // 继承来的本领:麻雀在吃东西
$bird->fly();  // 自己的本领:麻雀在天上飞// 造一条鱼
$fish = new Fish("金鱼");
$fish->eat();  // 继承来的本领:金鱼在吃东西
$fish->swim();  // 自己的本领:金鱼在水里游
?>

1.12,2 子类中调用父类成员

parent::关键字可以在子类里调用父类的方法,就像 "先按我爸教的方法做,再加上我自己的改进"。

<?php
class Dad {
    public function cook() {
        echo "爸爸的红烧肉做法:放酱油、糖、八角";
    }
}
​
class Son extends Dad {
    public function cook() {
        // 先按爸爸的方法做
        parent::cook();
        // 再加上自己的改进
        echo ",再加一点啤酒味道更好";
    }
}
​
$son = new Son();
$son->cook();  // 输出:爸爸的红烧肉做法:放酱油、糖、八角,再加一点啤酒味道更好
?>

1.12.3 protected

protected修饰的成员,就像家里的工具箱,自己家人(本类和子类)可以用,但外人不能用

<?php
class Grandpa {
    protected $secretRecipe = "祖传的饺子馅配方";
    
    protected function makeDumplings() {
        echo "用{$this->secretRecipe}做饺子";
    }
}
​
class Father extends Grandpa {
    public function cookDumplings() {
        // 子类可以用父类的protected成员
        $this->makeDumplings();
    }
}
​
$father = new Father();
$father->cookDumplings();  // 可以用
// $father->makeDumplings();  // 不行!外人不能直接用protected方法
?>

1.12.4 继承中的构造函数

如果子类有自己的构造函数,最好先调用一下父类的构造函数,就像 "先完成爸爸交代的任务,再做自己的事"

<?php
class Person {
    protected $name;
    
    public function __construct($name) {
        $this->name = $name;
        echo "我叫{$name}";
    }
}
​
class Teacher extends Person {
    private $subject;  // 教的科目
    
    public function __construct($name, $subject) {
        // 先调用父类的构造函数
        parent::__construct($name);
        // 再处理自己的事情
        $this->subject = $subject;
        echo ",我教{$subject}";
    }
}
​
$teacher = new Teacher("王老师", "数学");
// 输出:我叫王老师,我教数学
?>

1.12.5 $this详解

$this就是 "我自己" 的意思。在类的方法里用$this,指的就是当前这个对象。

<?php
class Animal {
    public function move() {
        // 让"自己"动起来
        $this->howToMove();
    }
}
​
class Rabbit extends Animal {
    // 兔子的移动方式
    public function howToMove() {
        echo "兔子蹦蹦跳跳";
    }
}
​
class Snake extends Animal {
    // 蛇的移动方式
    public function howToMove() {
        echo "蛇蜿蜒爬行";
    }
}
​
$rabbit = new Rabbit();
$rabbit->move();  // 输出:兔子蹦蹦跳跳(调用的是兔子自己的方法)$snake = new Snake();
$snake->move();  // 输出:蛇蜿蜒爬行(调用的是蛇自己的方法)
?>

在继承中,$this指的是实际创建的那个对象。比如用子类创建的对象,$this就指这个子类对象。

1.12.6 多重继承

PHP 不允许一个类同时继承多个父类,就像一个人不能有两个亲爸爸一样,会乱套的。

如果需要多个类的功能,可以用 "接口"(interface)来实现,一个类可以实现多个接口,就像一个人可以同时学语文老师、数学老师、英语老师的知识。

<?php
// 会做饭的接口
interface CanCook {
    public function cook();
}
​
// 会修东西的接口
interface CanRepair {
    public function repair();
}
​
// 全能选手,既会做饭又会修东西
class Handyman implements CanCook, CanRepair {
    public function cook() {
        echo "我会做饭";
    }
    
    public function repair() {
        echo "我会修东西";
    }
}
​
$person = new Handyman();
$person->cook();   // 输出:我会做饭
$person->repair(); // 输出:我会修东西
?>这样,Handyman 类就同时有了两个接口的能力。
​

这样,Handyman 类就同时有了两个接口的能力。