好的,各位观众老爷们,欢迎来到我的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
类是父类,定义了动物的基本属性(name
和color
)和方法(eat()
)。Dog
类是子类,使用extends Animal
继承了Animal
类的所有属性和方法。Dog
类还定义了自己的方法bark()
。- 我们可以像访问
Dog
类自己的属性和方法一样,访问从Animal
类继承来的属性和方法。
2. 继承的优势
- 代码重用: 避免重复编写相同的代码,提高开发效率。
- 代码组织: 将相关的类组织在一起,使代码结构更清晰。
- 可扩展性: 方便扩展现有类,添加新的功能。
3. 继承的注意事项
- 单一继承: PHP只支持单一继承,即一个类只能继承一个父类。不像某些语言支持多重继承,那样会导致“菱形继承”问题,想想都头疼!😵💫
-
访问控制: 父类的属性和方法可以通过访问控制修饰符(
public
、protected
、private
)来限制子类的访问权限。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
类是父类,定义了商品的基本属性(id
、name
、price
)和方法(getPrice()
、showDetails()
)。DigitalProduct
类和PhysicalProduct
类是子类,分别代表数字商品和实物商品,继承了Product
类的所有属性和方法。- 子类可以添加自己的属性和方法,比如
DigitalProduct
类的downloadLink
属性和PhysicalProduct
类的weight
属性和getShippingCost()
方法。 - 子类可以重写父类的方法,比如
showDetails()
方法,在父类方法的基础上添加自己的逻辑。使用parent::showDetails()
可以调用父类的showDetails()
方法。
三、主菜二:封装——保护你的隐私
封装,就是将对象的属性和方法隐藏起来,只允许通过特定的接口来访问。就像你的银行账户,你只能通过银行提供的渠道(ATM、网银等)来存取款,而不能直接打开银行的金库。🔒
1. 封装的语法
在PHP中,使用访问控制修饰符(public
、protected
、private
)来实现封装。
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
类的accountNumber
和balance
属性是private
的,只能在类内部访问。- 通过
getAccountNumber()
和getBalance()
方法可以获取账号和余额,但不能直接修改。 deposit()
和withdraw()
方法提供了存款和取款的功能,并且对金额进行了验证,保证了数据的安全性。
4. Getter和Setter方法
通常情况下,我们会为private
属性提供getter
和setter
方法,用于获取和设置属性的值。
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()
方法,表示支付操作。CreditCardPayment
和PayPalPayment
类实现了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()
抽象方法,表示计算面积的操作。Circle
和Rectangle
类继承了Shape
抽象类,分别实现了圆形和矩形的面积计算。printArea()
函数接受一个Shape
对象作为参数,可以接受任何Shape
的子类对象,并调用其getArea()
方法。
五、总结:OOP三大护法的威力
继承、封装和多态是OOP的三大核心特性,它们就像武林高手的内功、招式和轻功,缺一不可。掌握了这三大护法,你就能写出更加灵活、可维护、可扩展的PHP代码,成为真正的编程大师!🏆
- 继承: 代码重用的利器,站在巨人的肩膀上。
- 封装: 保护数据的盾牌,隐藏实现的细节。
- 多态: 灵活变化的法宝,适应不同的场景。
希望今天的脱口秀对大家有所帮助,下次有机会再和大家聊聊设计模式!拜拜!👋