PHP OOP:继承、封装与多态

好的,各位观众老爷们,欢迎来到我的PHP OOP脱口秀现场!今天咱们要聊的是PHP面向对象编程(OOP)的三大护法:继承、封装和多态。这哥仨,听起来高大上,其实就像你家楼下的煎饼果子摊,各有各的绝活,组合起来就能做出美味的软件大餐!🥞

一、开胃小菜:OOP基础回顾

在深入继承、封装和多态之前,咱们先快速回顾一下OOP的基础概念。别担心,不会让你昏昏欲睡,保证让你听得津津有味!

  • 对象(Object): 这是OOP的核心。你可以把对象想象成一个具体的实体,比如一辆汽车、一只猫咪、或者一个用户。它拥有自己的属性(特征)和方法(行为)。
  • 类(Class): 类是对象的蓝图或者模板。它定义了对象应该具有哪些属性和方法。你可以把类想象成煎饼果子摊的配方,有了配方,你就能做出无数个煎饼果子。
  • 属性(Property): 属性是对象的状态或特征。比如汽车的颜色、猫咪的毛发、用户的姓名。
  • 方法(Method): 方法是对象的行为或操作。比如汽车的行驶、猫咪的叫声、用户的登录。

二、主菜一:继承——站在巨人的肩膀上

继承,顾名思义,就是子类继承父类的属性和方法。就像你继承了你爸妈的颜值和智商(希望如此!🤣)。继承是OOP中代码重用的利器,可以避免重复编写相同的代码。

1. 继承的语法

在PHP中,使用extends关键字来实现继承。

<?php
class Animal { // 父类,动物
    public $name;
    public $color;

    public function eat() {
        echo "动物在吃东西...n";
    }
}

class Dog extends Animal { // 子类,狗,继承自Animal
    public function bark() {
        echo "汪汪汪!n";
    }
}

$dog = new Dog();
$dog->name = "旺财";
$dog->color = "黄色";
$dog->eat(); // 调用父类的方法
$dog->bark(); // 调用子类的方法

echo $dog->name . "是" . $dog->color . "的。n";
?>

代码解释:

  • Animal类是父类,定义了动物的基本属性(namecolor)和方法(eat())。
  • Dog类是子类,使用extends Animal继承了Animal类的所有属性和方法。
  • Dog类还定义了自己的方法bark()
  • 我们可以像访问Dog类自己的属性和方法一样,访问从Animal类继承来的属性和方法。

2. 继承的优势

  • 代码重用: 避免重复编写相同的代码,提高开发效率。
  • 代码组织: 将相关的类组织在一起,使代码结构更清晰。
  • 可扩展性: 方便扩展现有类,添加新的功能。

3. 继承的注意事项

  • 单一继承: PHP只支持单一继承,即一个类只能继承一个父类。不像某些语言支持多重继承,那样会导致“菱形继承”问题,想想都头疼!😵‍💫
  • 访问控制: 父类的属性和方法可以通过访问控制修饰符(publicprotectedprivate)来限制子类的访问权限。

    • public:公共的,子类可以自由访问。
    • protected:受保护的,子类可以访问,但类的外部不能访问。
    • private:私有的,只有父类自身可以访问,子类也不能访问。
  • final关键字: 可以使用final关键字来防止类被继承或方法被重写。

    • final class MyClass {}:表示MyClass不能被继承。
    • final public function myMethod() {}:表示myMethod不能被重写。

4. 继承的案例分析

来个稍微复杂一点的例子,模拟一个电商网站的商品类:

<?php
class Product { // 父类,商品
    public $id;
    public $name;
    public $price;

    public function __construct($id, $name, $price) {
        $this->id = $id;
        $this->name = $name;
        $this->price = $price;
    }

    public function getPrice() {
        return $this->price;
    }

    public function showDetails() {
        echo "ID: " . $this->id . "n";
        echo "名称: " . $this->name . "n";
        echo "价格: " . $this->getPrice() . "n";
    }
}

class DigitalProduct extends Product { // 子类,数字商品
    public $downloadLink;

    public function __construct($id, $name, $price, $downloadLink) {
        parent::__construct($id, $name, $price); // 调用父类的构造函数
        $this->downloadLink = $downloadLink;
    }

    public function showDetails() {
        parent::showDetails(); // 调用父类的showDetails()方法
        echo "下载链接: " . $this->downloadLink . "n";
    }
}

class PhysicalProduct extends Product { // 子类,实物商品
    public $weight;

    public function __construct($id, $name, $price, $weight) {
        parent::__construct($id, $name, $price);
        $this->weight = $weight;
    }

    public function getShippingCost() {
        // 根据重量计算运费,这里只是个例子
        return $this->weight * 0.5;
    }

    public function showDetails() {
        parent::showDetails();
        echo "重量: " . $this->weight . "kgn";
        echo "运费: " . $this->getShippingCost() . "元n";
    }
}

$digitalProduct = new DigitalProduct(1, "PHP教程", 99.00, "http://example.com/php.pdf");
$physicalProduct = new PhysicalProduct(2, "T恤", 129.00, 0.2);

$digitalProduct->showDetails();
$physicalProduct->showDetails();
?>

代码解释:

  • Product类是父类,定义了商品的基本属性(idnameprice)和方法(getPrice()showDetails())。
  • DigitalProduct类和PhysicalProduct类是子类,分别代表数字商品和实物商品,继承了Product类的所有属性和方法。
  • 子类可以添加自己的属性和方法,比如DigitalProduct类的downloadLink属性和PhysicalProduct类的weight属性和getShippingCost()方法。
  • 子类可以重写父类的方法,比如showDetails()方法,在父类方法的基础上添加自己的逻辑。使用parent::showDetails()可以调用父类的showDetails()方法。

三、主菜二:封装——保护你的隐私

封装,就是将对象的属性和方法隐藏起来,只允许通过特定的接口来访问。就像你的银行账户,你只能通过银行提供的渠道(ATM、网银等)来存取款,而不能直接打开银行的金库。🔒

1. 封装的语法

在PHP中,使用访问控制修饰符(publicprotectedprivate)来实现封装。

  • public:公共的,任何地方都可以访问。
  • protected:受保护的,类自身、子类和父类内部可以访问。
  • private:私有的,只有类自身可以访问。

2. 封装的优势

  • 信息隐藏: 保护对象内部的数据,防止外部直接修改,提高安全性。
  • 模块化: 将对象分解成独立的模块,降低耦合度,提高可维护性。
  • 灵活性: 可以在不影响外部代码的情况下修改对象内部的实现,提高灵活性。

3. 封装的案例分析

<?php
class BankAccount {
    private $accountNumber;
    private $balance;

    public function __construct($accountNumber, $initialBalance) {
        $this->accountNumber = $accountNumber;
        $this->balance = $initialBalance;
    }

    public function getAccountNumber() {
        return $this->accountNumber;
    }

    public function getBalance() {
        return $this->balance;
    }

    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
            echo "存款成功,余额为:" . $this->balance . "n";
        } else {
            echo "存款金额必须大于0n";
        }
    }

    public function withdraw($amount) {
        if ($amount > 0 && $amount <= $this->balance) {
            $this->balance -= $amount;
            echo "取款成功,余额为:" . $this->balance . "n";
        } else {
            echo "取款金额无效或余额不足n";
        }
    }
}

$account = new BankAccount("1234567890", 1000);
//echo $account->balance; // 报错,因为balance是private的
echo "账号:" . $account->getAccountNumber() . "n";
echo "余额:" . $account->getBalance() . "n";
$account->deposit(500);
$account->withdraw(200);
$account->withdraw(2000); // 余额不足
?>

代码解释:

  • BankAccount类的accountNumberbalance属性是private的,只能在类内部访问。
  • 通过getAccountNumber()getBalance()方法可以获取账号和余额,但不能直接修改。
  • deposit()withdraw()方法提供了存款和取款的功能,并且对金额进行了验证,保证了数据的安全性。

4. Getter和Setter方法

通常情况下,我们会为private属性提供gettersetter方法,用于获取和设置属性的值。

  • getter方法:用于获取属性的值,通常以get开头,比如getName()getBalance()
  • setter方法:用于设置属性的值,通常以set开头,比如setName()setBalance()

四、主菜三:多态——千变万化

多态,是指对象可以表现出多种形态。就像水,可以是液态、固态、气态,也可以是冰淇淋、饮料等等。🍦

1. 多态的实现方式

在PHP中,多态主要通过以下两种方式实现:

  • 接口(Interface): 定义一组方法,但不实现它们。类可以实现一个或多个接口,必须实现接口中定义的所有方法。
  • 抽象类(Abstract Class): 定义一些抽象方法,但不实现它们。类可以继承一个抽象类,必须实现抽象类中定义的所有抽象方法。

2. 接口和抽象类的区别

特性 接口 (Interface) 抽象类 (Abstract Class)
方法实现 只能定义方法签名 可以定义抽象方法和具体方法
属性 不能定义属性 可以定义属性
继承关系 可以实现多个接口 只能继承一个抽象类
关键字 interface, implements abstract, extends

3. 多态的优势

  • 可扩展性: 方便添加新的类,而不需要修改现有代码。
  • 灵活性: 可以根据不同的情况使用不同的对象,提高代码的灵活性。
  • 解耦: 降低类之间的耦合度,提高代码的可维护性。

4. 多态的案例分析

使用接口实现多态:

<?php
interface PaymentMethod { // 支付方式接口
    public function pay($amount);
}

class CreditCardPayment implements PaymentMethod { // 信用卡支付
    public function pay($amount) {
        echo "使用信用卡支付了" . $amount . "元n";
    }
}

class PayPalPayment implements PaymentMethod { // PayPal支付
    public function pay($amount) {
        echo "使用PayPal支付了" . $amount . "元n";
    }
}

class Order {
    private $paymentMethod;

    public function __construct(PaymentMethod $paymentMethod) {
        $this->paymentMethod = $paymentMethod;
    }

    public function checkout($amount) {
        $this->paymentMethod->pay($amount);
    }
}

$creditCardPayment = new CreditCardPayment();
$payPalPayment = new PayPalPayment();

$order1 = new Order($creditCardPayment);
$order1->checkout(100); // 使用信用卡支付

$order2 = new Order($payPalPayment);
$order2->checkout(200); // 使用PayPal支付
?>

代码解释:

  • PaymentMethod接口定义了一个pay()方法,表示支付操作。
  • CreditCardPaymentPayPalPayment类实现了PaymentMethod接口,分别实现了信用卡支付和PayPal支付。
  • Order类接受一个PaymentMethod对象作为参数,可以在运行时选择不同的支付方式。

使用抽象类实现多态:

<?php
abstract class Shape { // 形状抽象类
    abstract public function getArea();
}

class Circle extends Shape { // 圆形
    private $radius;

    public function __construct($radius) {
        $this->radius = $radius;
    }

    public function getArea() {
        return pi() * $this->radius * $this->radius;
    }
}

class Rectangle extends Shape { // 矩形
    private $width;
    private $height;

    public function __construct($width, $height) {
        $this->width = $width;
        $this->height = $height;
    }

    public function getArea() {
        return $this->width * $this->height;
    }
}

function printArea(Shape $shape) {
    echo "面积:" . $shape->getArea() . "n";
}

$circle = new Circle(5);
$rectangle = new Rectangle(4, 6);

printArea($circle); // 输出圆形的面积
printArea($rectangle); // 输出矩形的面积
?>

代码解释:

  • Shape抽象类定义了一个getArea()抽象方法,表示计算面积的操作。
  • CircleRectangle类继承了Shape抽象类,分别实现了圆形和矩形的面积计算。
  • printArea()函数接受一个Shape对象作为参数,可以接受任何Shape的子类对象,并调用其getArea()方法。

五、总结:OOP三大护法的威力

继承、封装和多态是OOP的三大核心特性,它们就像武林高手的内功、招式和轻功,缺一不可。掌握了这三大护法,你就能写出更加灵活、可维护、可扩展的PHP代码,成为真正的编程大师!🏆

  • 继承: 代码重用的利器,站在巨人的肩膀上。
  • 封装: 保护数据的盾牌,隐藏实现的细节。
  • 多态: 灵活变化的法宝,适应不同的场景。

希望今天的脱口秀对大家有所帮助,下次有机会再和大家聊聊设计模式!拜拜!👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注