从零开始编写PHP学习系列教程
第五章:面向对象编程
面向对象编程(OOP)是一种编程范式,它使用"对象"来设计软件。在PHP中,类和对象是OOP的核心组成部分。
5.1 类与对象
类的定义:在PHP中,类是一种编程结构,用于定义和创建对象。它是一种自定义的数据类型,可以包含属性和方法。
- 属性(成员变量):属性是在类中定义的变量。它们用于存储对象的状态信息。属性声明时可以指定其可见性(public、protected、private),以控制从类外部的访问权限。
class Car {
public $color;
protected $manufacturer;
private $model;
}
在面向对象编程(OOP)中,属性(也称为成员变量或字段)的可见性可以通过关键字 public、protected 和 private 来设定,这是访问控制修饰符,用于控制类外部和其他类对这些属性的访问权限:
-
public:
- 公有的(public)属性可以在任何地方被访问,无论是在类的内部还是外部,包括子类中。
class MyClass { public $publicVar; } $obj = new MyClass(); $obj->publicVar = 'Hello'; // 任何地方都可以直接访问和修改
-
protected:
- 受保护的(protected)属性只能在该类本身及其子类中访问,但在类外部不能直接访问。
class MyClass { protected $protectedVar; } class ChildClass extends MyClass { public function displayProtected() { echo $this->protectedVar; // 子类中可以访问 } } $child = new ChildClass(); $child->protectedVar = 'World'; // 错误,无法在类外部直接访问
-
private:
- 私有的(private)属性只能在定义它们的类的内部访问,即使在子类中也无法访问。
class MyClass { private $privateVar; } class ChildClass extends MyClass { public function displayPrivate() { // 错误,无法在子类中访问父类的私有属性 // echo $this->privateVar; } } $obj = new MyClass(); $obj->privateVar = '!'; // 错误,无法在类外部直接访问 // echo $obj->privateVar;
总结来说,访问控制修饰符用于封装(Encapsulation)这一OOP原则的实现,有助于隐藏类的内部实现细节,提高代码的安全性和可维护性。
- 方法(成员函数):方法是在类中定义的函数。它们用于执行操作或定义对象的行为。方法也可以具有不同的可见性。
class Car {
public function setColor($color) {
$this->color = $color;
}
public function getColor() {
return $this->color;
}
}
构造函数和析构函数:
- 构造函数:是一种特殊的方法,每当创建类的新对象时自动调用。它通常用于初始化对象属性或执行启动任务。在PHP中,构造函数命名为__construct()。
class Car {
public function __construct($color) {
$this->color = $color;
}
}
$car = new Car('blue'); // 创建一个蓝色的汽车对象
- 析构函数:是在对象不再需要时自动调用的特殊方法。它用于进行清理工作,如释放资源、关闭文件等。在PHP中,析构函数命名为__destruct()。
class Car {
public function __construct($color) {
$this->color = $color;
}
public function __destruct() {
echo "销毁 {$this->color} 色的汽车对象。";
}
}
this关键字:
- this是一个特殊的指针,它在类的方法中使用,用于访问类的属性和方法。this指向当前对象的实例。
class Car {
public $color;
public function setColor($color) {
$this->color = $color; // 使用this访问当前对象的color属性
}
}
应用场景:
- 构造函数:用于初始化新创建的对象。例如,当创建一个Car对象时,你可能需要为它指定一个颜色。
- 析构函数:用于执行对象销毁前的最后操作,如关闭数据库连接、释放资源等。
- this关键字:在对象内部访问其属性和方法时使用,尤其是在需要区分局部变量和对象属性时。
通过类和对象,可以将现实世界的实体和它们的行为模拟到编程环境中,使得代码更加模块化和易于管理。面向对象编程不仅有助于提高代码的重用性,还能提高开发效率和软件质量。
5.2 面向对象特性
继承(Inheritance)
继承是面向对象编程中的一种重要特性,它允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以使用父类已经定义好的方法和属性,并且可以在此基础上添加新的方法或属性。例如:
class Animal {
public $name;
public function __construct($name) {
$this->name = $name;
}
public function eat() {
echo $this->name . " is eating.";
}
}
class Dog extends Animal {
public function bark() {
echo $this->name . " is barking.";
}
}
$dog = new Dog("Buddy");
$dog->eat(); // Output: Buddy is eating.
$dog->bark(); // Output: Buddy is barking.
封装(Encapsulation)
封装是将数据和操作数据的方法打包在一起的概念,可以通过访问修饰符(public、private、protected)控制属性和方法的访问权限。这样可以隐藏对象的内部细节,使得对象的使用者只能通过公共方法来访问对象,而无需了解其内部实现。例如:
class Car {
private $model;
protected $color;
public function __construct($model, $color) {
$this->model = $model;
$this->color = $color;
}
public function getModel() {
return $this->model;
}
public function getColor() {
return $this->color;
}
}
$car = new Car("Toyota", "red");
echo $car->getModel(); // Output: Toyota
echo $car->getColor(); // Error: Cannot access protected property
多态(Polymorphism)
多态是指同一个方法调用在不同的对象上有不同的行为。它允许子类重写父类的方法,实现方法的多态性。例如:
class Shape {
public function draw() {
// Default implementation
}
}
class Circle extends Shape {
public function draw() {
echo "Drawing a circle.";
}
}
class Square extends Shape {
public function draw() {
echo "Drawing a square.";
}
}
function drawShape(Shape $shape) {
$shape->draw();
}
$circle = new Circle();
$square = new Square();
drawShape($circle); // Output: Drawing a circle.
drawShape($square); // Output: Drawing a square.
抽象类和接口的设计原则
抽象类和接口都是用来定义规范的方式,它们都不能被实例化。抽象类可以包含抽象方法和具体方法,而接口只能包含抽象方法。抽象类用于具有相似特征的类之间的共性提取,而接口用于定义类之间的约定。设计原则包括:
- 单一职责原则(Single Responsibility Principle):一个类应该只有一个引起变化的原因。
- 开放-封闭原则(Open-Closed Principle):软件实体应该对扩展开放,对修改关闭。
- 里氏替换原则(Liskov Substitution Principle):子类型必须能够替换其基类型。
- 依赖倒置原则(Dependency Inversion Principle):高层模块不应该依赖于底层模块,两者都应该依赖于抽象。
final关键字和魔术方法
final关键字
在类的定义中,使用final关键字可以阻止类被继承或方法被重写。例如:
final class FinalClass {
// Class implementation
}
class ChildClass extends FinalClass {
// Error: Cannot inherit from final class FinalClass
}
魔术方法
魔术方法是在特定情况下自动调用的方法,以双下划线开头和结尾。常见的魔术方法包括:
- __construct():在创建对象时自动调用的构造方法。
- __destruct():在对象被销毁时自动调用的析构方法。
- __call():在调用不存在的方法时自动调用的方法。
- __get():在访问不存在或不可访问的属性时自动调用的方法。
- __set():在对不存在或不可访问的属性赋值时自动调用的方法。
class MagicClass {
public function __construct() {
echo "Constructor called.";
}
public function __destruct() {
echo "Destructor called.";
}
public function __call($name, $arguments) {
echo "Calling undefined method: $name";
}
public function __get($name) {
echo "Getting undefined property: $name";
}
public function __set($name, $value) {
echo "Setting undefined property: $name = $value";
}
}
$obj = new MagicClass(); // Output: Constructor called.
$obj->nonExistentMethod(); // Output: Calling undefined method: nonExistentMethod
$obj->nonExistentProperty; // Output: Getting undefined property: nonExistentProperty
$obj->nonExistentProperty = 123; // Output: Setting undefined property: nonExistentProperty = 123
unset($obj); // Output: Destructor called.
这些特性和原则为面向对象编程提供了强大的灵活性和可维护性,使得代码更加模块化和可扩展。