面向对象编程(Object-Oriented Programming,简称OOP)是一种以“对象”为中心的编程范式。和传统的面向过程编程不同——在面向过程里,我们写的是一个个按顺序执行的函数,数据在函数之间传递处理;而在OOP中,数据和对数据的操作被封装在一起形成对象,程序由这些对象之间的交互来驱动。PHP从版本5开始对OOP提供了比较完善的支持,掌握面向对象编程的概念,能让代码结构更清晰、复用性更高,在团队协作和大型项目中的优势尤其明显。
下面我们围绕PHP面向对象编程的核心概念,逐一展开说明,每个概念都附带可运行的示例代码。
一、类与对象(Class & Object)
类是面向对象编程的基础单元,可以理解为一个创建对象的模板或蓝图。类定义了这类对象应该具备哪些属性(数据)和方法(行为)。对象则是根据类这个蓝图创建出来的具体实例——一个类可以创建出多个独立的对象,每个对象拥有自己的属性值。
用生活中的例子来理解:类好比是一张“手机设计图纸”,规定了手机应该有的颜色、型号、存储容量这些属性,以及打电话、拍照这些功能。对象就是用这张图纸生产出来的具体手机——你手上的那一部、我手上的这一部,型号相同但各自存储的数据不同。
PHP中定义类和创建对象的语法
<?php
class 类名 {
// 属性(成员变量)
// 方法(成员函数)
}
$对象变量 = new 类名();
?>
new关键字用于根据类创建对象实例。用var_dump()可以查看对象的内部结构,方便调试。
示例1:基础类与对象的使用
<?php
class Student {
private $name = "张三";
public function showName() {
echo $this->name;
}
}
$stu = new Student();
$stu->showName();
?>
输出结果
张三
这里Student类有一个私有属性$name和一个公有方法showName()。$this是PHP中的一个特殊关键字,指向调用当前方法的那个对象实例。私有属性不能从类外部直接访问(写$stu->name会报错),只能通过类内部定义的方法来操作,这是封装的一种体现。
示例2:用var_dump()查看对象结构
<?php
class Book {
public $title = "PHP面向对象编程实战";
private $price = 59.80;
}
$book = new Book();
var_dump($book);
?>
输出结果
object(Book)#1 (2) {
["title"] => string(27) "PHP面向对象编程实战"
["price":"Book":private] => float(59.8)
}
var_dump()清晰地展示了对象所属的类、属性名称、属性可见性以及值,在排查属性赋值问题时很实用。
二、继承(Inheritance)
继承允许一个类(子类)从另一个类(父类)那里继承属性和方法。子类既可以直接使用父类已有的功能,也可以覆盖(重写)父类的方法来实现自己的独特行为。继承的核心价值是减少代码重复——公共的逻辑写在父类里,各个子类只关注自己的差异化部分。
语法结构
class 父类 {
// 父类的属性和方法
}
class 子类 extends 父类 {
// 子类可以新增或重写属性和方法
}
示例:动物类与狗类的继承关系
<?php
class Animal {
public function makeSound() {
return "动物发出某种声音";
}
}
class Dog extends Animal {
public function makeSound() {
return "汪汪!";
}
}
$pet = new Dog();
echo $pet->makeSound();
?>
输出结果
汪汪!
Dog继承自Animal,并重写了makeSound()方法。子类重写父类方法的这种行为属于方法覆盖,是面向对象多态性的基础表现之一。
个人经验分享:刚接触继承时,容易忍不住建一个“万能基类”把所有公共方法塞进去。但继承层次太深会降低代码可读性和灵活性。项目开发中,我习惯保持继承层级在2到3层以内。如果发现一个类需要从多个不同的类获取功能,更推荐使用Trait(PHP的特性复用机制)或组合方式,而不是硬着头皮套多层继承。
三、多态(Polymorphism)
多态的字面意思是“多种形态”。在面向对象编程中,多态指的是不同的类可以实现相同名称的方法,调用方不需要知道对象具体属于哪个类,只需要知道这个方法存在,就能保证对象会以自己的方式响应。
示例:鸟和飞机都有fly()方法
<?php
class Bird {
public function fly() {
return "鸟在扇动翅膀飞行";
}
}
class Airplane {
public function fly() {
return "飞机依靠引擎推力飞行";
}
}
function startFlying($obj) {
echo $obj->fly() . "\n";
}
startFlying(new Bird());
startFlying(new Airplane());
?>
输出结果
鸟在扇动翅膀飞行
飞机依靠引擎推力飞行
函数startFlying()接受任意一个拥有fly()方法的对象,输出内容由对象自身的方法实现来决定。这种“同一个接口,不同行为”的模式就是多态的直观体现。
四、数据抽象(Data Abstraction)
数据抽象是指对外只暴露必要的操作接口,隐藏内部复杂的实现细节。在PHP中,抽象通过抽象类和抽象方法来实现。抽象类不能被直接实例化,只能作为其他类的父类存在。抽象方法只声明方法签名,不写方法体,强制子类必须实现该方法。
语法结构
abstract class 抽象类名 {
abstract public function 方法名();
}
示例:抽象交通工具类
<?php
abstract class Vehicle {
abstract public function startEngine();
}
class Motorcycle extends Vehicle {
public function startEngine() {
return "摩托车:踩下启动杆,发动机点火";
}
}
$bike = new Motorcycle();
echo $bike->startEngine();
?>
输出结果
摩托车:踩下启动杆,发动机点火
Vehicle作为抽象类,规定了所有交通工具都必须有startEngine()这个方法,但每种车型的启动方式不同,具体实现留给子类去完成。
五、成员函数(Member Function)
成员函数就是定义在类内部的方法,用于操作对象的属性或执行对象相关的业务逻辑。通过成员函数操作属性,而不是直接从外部访问属性,是实现封装的基本手段。
示例:圆形面积计算
<?php
class Circle {
private $radius;
public function __construct($radius) {
$this->radius = $radius;
}
public function getArea() {
return 3.14 * $this->radius * $this->radius;
}
}
$circle = new Circle(5);
echo "圆的面积是:" . $circle->getArea();
?>
输出结果
圆的面积是:78.5
getArea()是Circle类的一个成员函数,它访问了私有属性$radius并返回计算结果。外部代码不需要知道面积公式的细节,调用getArea()就能拿到结果。
六、构造函数与析构函数(Constructor & Destructor)
构造函数(__construct())是在对象被创建时自动调用的特殊方法,通常用于初始化对象属性、注入依赖等操作。
析构函数(__destruct())在对象被销毁时自动调用——比如脚本执行结束、对象用unset()主动释放、或者指向对象的变量被重新赋值导致原对象没有引用时。析构函数常用于执行清理工作,比如关闭文件句柄、释放数据库连接。
示例:带构造函数和析构函数的类
<?php
class FileLogger {
private $handle;
public function __construct($filename) {
$this->handle = fopen($filename, 'a');
echo "日志文件已打开<br>";
}
public function writeLog($message) {
$time = date('Y-m-d H:i:s');
fwrite($this->handle, "[$time] $message\n");
}
public function __destruct() {
fclose($this->handle);
echo "日志文件已关闭<br>";
}
}
$logger = new FileLogger("app_2026.log");
$logger->writeLog("用户登录系统");
unset($logger); // 主动销毁对象,触发析构函数
?>
输出结果
日志文件已打开
日志文件已关闭
构造函数在new FileLogger()时执行,打开了文件;析构函数在unset($logger)时执行,关闭了文件。这种“构造时获取资源、析构时释放资源”的模式,能有效避免资源泄露。
个人建议:析构函数在开发中用得相对较少,因为PHP脚本通常执行完就自动释放所有资源。但在长时间运行的守护进程、或者使用Swoole这类常驻内存的PHP运行环境时,析构函数的资源释放逻辑就变得比较重要——对象不销毁,资源就一直占着。
七、封装(Encapsulation)
封装是指把数据和操作数据的方法捆绑在一起,并控制外部对这些数据的访问权限。PHP通过访问修饰符public、protected、private来实现封装控制:public可从任何地方访问,protected限本类和子类内部访问,private仅限本类内部访问。
示例:银行账户封装
<?php
class BankAccount {
private $balance = 0;
public function deposit($amount) {
if ($amount > 0) {
$this->balance += $amount;
}
}
public function getBalance() {
return $this->balance;
}
}
$account = new BankAccount();
$account->deposit(500);
$account->deposit(-200); // 负数被忽略
echo "账户余额:" . $account->getBalance() . " 元";
?>
输出结果
账户余额:500 元
$balance被声明为private,外部无法直接修改,只能通过deposit()方法存入,而deposit()内部做了金额合法性校验。这种封装方式保障了数据的完整性和安全性。
八、重载(Overloading)
PHP中的“重载”和其他语言(如Java的编译时重载)含义不同。PHP的重载指的是通过魔术方法动态地处理对类中不可访问或不存在的方法和属性的调用。常用的两个魔术方法是__call()(处理方法调用)和__callStatic()(处理静态方法调用)。
示例:动态处理add()方法的不同参数数量
<?php
class MathTool {
public function __call($methodName, $arguments) {
if ($methodName === 'sum') {
return array_sum($arguments);
}
return null;
}
}
$tool = new MathTool();
echo "2个数相加:" . $tool->sum(3, 7) . "\n";
echo "4个数相加:" . $tool->sum(2, 4, 6, 8);
?>
输出结果
2个数相加:10
4个数相加:20
MathTool类里实际上没有显式定义sum()方法,但通过__call(),所有对sum()的调用都会被拦截并用array_sum()统一处理,无论传多少参数都能正常工作。
九、$this关键字的作用
$this是PHP面向对象编程中一个比较常用的关键字,它代表当前对象的引用。在类的内部,当需要访问当前对象的属性或调用当前对象的方法时,就需要用$this->属性名或$this->方法名()的语法。
示例:用$this访问和设置属性
<?php
class Mobile {
public $model;
public function setModel($model) {
$this->model = $model;
}
public function getModel() {
return $this->model;
}
}
$phone = new Mobile();
$phone->setModel("华为Mate 70");
echo "手机型号:" . $phone->getModel();
?>
输出结果
手机型号:华为Mate 70
在setModel()方法里,$this->model指向的是当前这个Mobile实例的$model属性。如果没有$this,PHP会把$model当成方法内部的局部变量,和对象的属性毫无关系。
本节课程知识要点
-
类是创建对象的模板,用
class关键字定义;对象是用new关键字从类实例化出来的具体个体。 -
继承通过
extends关键字实现子类对父类属性和方法的复用,建议控制继承层级,保持代码的可读性。 -
多态让不同类可以用相同的方法名提供各自的实现行为,增强了代码扩展灵活性。
-
抽象类用
abstract声明,不能被直接实例化,其抽象方法强制子类完成具体实现。 -
构造函数(
__construct())在对象创建时自动执行,适合做初始化;析构函数(__destruct())在对象销毁时调用,适合做资源清理。 -
封装通过
public、protected、private控制属性方法的访问范围,将数据与操作绑定在一起,保护数据完整性。 -
PHP的重载依赖
__call()等魔术方法,实现动态处理方法调用的能力,与Java等语言的编译时重载机制不同。 -
$this关键字在类内部指向当前对象实例,是访问对象自身属性和方法的途径。
面向对象编程在PHP中是一套体系化的思维方式,从类与对象的基本构建,到继承、多态、封装等概念的灵活运用,再到构造函数和析构函数对对象生命周期的管理,这些概念之间相互关联。把这些基础打扎实,后续学习设计模式、依赖注入、自动化测试等内容会顺畅很多。