面向对象编程(OOP)有三个最核心、最重要的特性,理解它们,你就掌握了 OOP 的灵魂。这三个特性分别是:封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)。这三个特性让程序更安全、更高效、更易维护。
封装—把复杂的东西藏起来
封装就是把数据和操作数据的方法绑定在一起,同时隐藏内部细节,对外只暴露必要的接口。就像你用手机:你只需要知道按下按钮就能打电话,手机内部的电路、芯片,你根本不需要知道。
示例
classPerson {
private$name;
publicfunctionsetName($name) {
$this->name=$name; // 提供公共方法修改属性
}
publicfunctiongetName() {
return$this->name; // 提供公共方法访问属性
}
}
继承—代码可以复用
继承就是子类自动拥有父类的属性和方法,可以直接使用,也可以扩展或重写。就像:“交通工具”有轮子、有速度,“汽车”、“摩托车” 都继承了这些功能,但可以有各自的新功能。
PHP 中继承的语法
class父类 {
// 父类的属性和方法
}
class子类extends父类 {
// 子类可以添加新属性和新方法
}
示例
classAnimal {
publicfunctioneat() {
echo"动物正在吃饭<br>";
}
}
classDogextendsAnimal {
publicfunctionbark() {
echo"汪汪叫<br>";
}
}
$dog=newDog();
$dog->eat(); // 调用父类方法
$dog->bark(); // 调用子类方法
访问控制对继承的影响
访问控制不仅影响 属性和方法的访问权限,还直接影响 继承时子类能不能访问父类的成员。
修饰符 | 子类是否可以继承 | 子类是否可以访问 |
---|---|---|
public |
✅ | ✅ |
protected |
✅ | ✅(只能在类内部和子类访问) |
private |
❌(无法继承) | ❌(无法访问) |
classA {
public$a="公共";
protected$b="受保护";
private$c="私有";
}
classBextendsA {
publicfunctionshow() {
echo$this->a; // ✅
echo$this->b; // ✅
// echo $this->c; // ❌ 无法访问
}
}
口诀:Public 谁都能用,Protected 子类可用,Private 自家专用。
方法和属性重写
方法重写(Overriding) 指的是:在子类中,定义一个与父类同名的方法,用于替换父类的实现。简单理解:子类重新定义父类的方法,子类的方法会覆盖父类的方法。
classParentClass {
publicfunctionshow() {
echo"我是父类的方法<br>";
}
}
classChildClassextendsParentClass {
publicfunctionshow() { // 重写父类方法
echo"我是子类的方法<br>";
}
}
$obj=newChildClass();
$obj->show(); // 输出:我是子类的方法
final 关键字
作用:
-
防止类被继承
-
防止类的方法被重写
如果在一个类前加final,那么这个类就不能被继承;
finalclassmyClass {
// 类的内容
}
如果在一个方法前加final,那么这个方法就不能被重写,注意:final不能用于属性
多态—相同的接口,不同的行为
多态就是同一个方法,不同对象可以有不同的表现。简单来说就是相同的方法,不同的对象,不同的结果。就像:“交通工具”都有“运行”这个功能,飞机飞,汽车跑,轮船游都叫“运行”,但是表现完全不同。
多态的三种主流实现:
实现方式 | 描述 |
---|---|
类方法重写 | 子类继承父类并重写同名方法 |
接口实现 | 不同类实现相同接口方法 |
抽象类实现 | 抽象父类强制子类实现抽象方法 |
方式一:父类方法重写(简单易用)
父类引用接受不同子类对象、子类重写父类方法,表现不同。
classAnimal {
publicfunctionspeak() {
echo"动物在叫<br>";
}
}
classDogextendsAnimal {
publicfunctionspeak() {
echo"汪汪叫<br>";
}
}
classCatextendsAnimal {
publicfunctionspeak() {
echo"喵喵叫<br>";
}
}
functionmakeSound(Animal$animal) {
$animal->speak();
}
makeSound(newDog()); // 输出:汪汪叫
makeSound(newCat()); // 输出:喵喵叫
方式二:接口实现(推荐)
什么是接口(Interface)?
接口(Interface) 就是一种约定和规范,规定了一个类必须要实现哪些方法。接口 = 只定义方法,不写具体内容。实现接口的类 = 必须实现接口里所有的方法。
假设:所有的打印机都必须具备一个 print()
方法,不管是激光打印机、喷墨打印机、针式打印机。
打印接口:
interfacePrinter {
publicfunctionprint();
}
激光打印机:
classLaserPrinterimplementsPrinter {
publicfunctionprint() {
echo"激光打印机正在打印<br>";
}
}
喷墨打印机:
classInkjetPrinterimplementsPrinter {
publicfunctionprint() {
echo"喷墨打印机正在打印<br>";
}
}
这个时候你只需要
functiondoPrint(Printer$printer) {
$printer->print();
}
doPrint(newLaserPrinter()); // 激光打印机正在打印
doPrint(newInkjetPrinter()); // 喷墨打印机正在打印
接口的特点
特性 | 说明 |
---|---|
只定义方法,不写实现 | 接口只能写方法声明,不能写方法内容 |
只能包含常量和方法声明 | 接口不能包含属性 |
类必须全部实现接口方法 | 否则会报错 |
支持多接口继承 | 一个类可以同时实现多个接口,支持行为组合 |
接口的语法结构
// 定义接口
interface接口名 {
publicfunction方法名();
}
// 实现接口
class类名implements接口名 {
publicfunction方法名() {
// 方法具体实现
}
}
接口的实际应用场景
场景 | 描述 |
---|---|
支付系统 | 支付接口,支持微信、支付宝、银联,不同类实现同一个支付接口 |
日志系统 | 日志接口,支持文件日志、数据库日志、远程日志 |
消息通知 | 通知接口,支持短信、邮件、APP 推送,不同通知方式统一调用 |
插件扩展开发 | 统一插件接口,方便后期扩展和替换,不影响原有主程序 |
方式三:抽象类实现
抽象类(Abstract Class) 是一种不完整的类,它不能被直接实例化,必须由子类去继承和补充实现。通俗理解:抽象类 = 半成品,子类 = 完整成品
抽象类的特点:
特点 | 说明 |
---|---|
不能被实例化 | 只能用作父类,不能直接 new 出对象 |
可以包含抽象方法 | 抽象方法只有声明,没有实现,子类必须实现 |
可以包含普通方法 | 抽象类可以写普通的公共方法,子类可以直接使用 |
可以包含属性 | 抽象类可以有自己的成员属性 |
支持继承和代码复用 | 子类继承抽象类,可以使用父类已经写好的方法和属性 |
抽象类的语法结构
// 定义抽象类
abstractclassAnimal {
public$name;
// 普通方法
publicfunctionsayHello() {
echo"你好,我是一个动物<br>";
}
// 抽象方法(不写内容)
abstractpublicfunctionspeak();
}
// 子类必须实现抽象方法
classDogextendsAnimal {
publicfunctionspeak() {
echo"汪汪汪<br>";
}
}
$dog=newDog();
$dog->sayHello(); // 你好,我是一个动物
$dog->speak(); // 汪汪汪
原文始发于微信公众号(风铃情报站):PHP基础-面向对象的三大特性
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论