面向对象编程概述
面向对象编程(OOP)是一种编程范式,它使用"对象"来设计应用程序和软件。PHP从版本5开始全面支持面向对象编程。
OOP的主要概念
- 类(Class): 对象的蓝图或模板
- 对象(Object): 类的实例
- 属性(Properties): 对象的特征或数据
- 方法(Methods): 对象的行为或功能
- 继承(Inheritance): 子类继承父类的特性
- 封装(Encapsulation): 隐藏对象的内部实现细节
- 多态(Polymorphism): 不同对象对同一消息做出不同响应
- 抽象(Abstraction): 简化复杂现实,只关注相关特征
OOP的优势:
- 代码重用: 通过继承实现代码复用
- 模块化: 代码组织更清晰,易于维护
- 扩展性: 易于添加新功能
- 安全性: 通过封装保护数据
- 团队协作: 不同开发者可以负责不同类
类和对象
类是对象的模板,对象是类的实例。
定义类和创建对象
<?php
// 定义一个类
class Car {
// 属性
public $brand;
public $color;
public $price;
// 构造方法
public function __construct($brand, $color, $price) {
$this->brand = $brand;
$this->color = $color;
$this->price = $price;
}
// 方法
public function getInfo() {
return "这是一辆" . $this->color . "的" . $this->brand . ",价格:" . $this->price;
}
public function startEngine() {
return "引擎已启动!";
}
}
// 创建对象
$car1 = new Car("丰田", "红色", "150000");
$car2 = new Car("本田", "蓝色", "180000");
// 调用方法
echo $car1->getInfo(); // 输出:这是一辆红色的丰田,价格:150000
echo "<br>";
echo $car2->startEngine(); // 输出:引擎已启动!
?>
构造方法和析构方法
构造方法和析构方法示例
<?php
class Person {
public $name;
public $age;
// 构造方法
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
echo "创建Person对象: $name<br>";
}
// 析构方法
public function __destruct() {
echo "销毁Person对象: $this->name<br>";
}
public function introduce() {
return "我是$this->name,今年$this->age岁。";
}
}
$person1 = new Person("张三", 25);
echo $person1->introduce() . "<br>";
$person2 = new Person("李四", 30);
echo $person2->introduce() . "<br>";
// 对象销毁时会自动调用析构方法
unset($person1);
unset($person2);
?>
访问控制修饰符
PHP提供了三种访问控制修饰符:
| 修饰符 | 描述 | 访问范围 |
|---|---|---|
public |
公有的 | 在任何地方都可以访问 |
protected |
受保护的 | 在类内部和子类中可以访问 |
private |
私有的 | 只能在类内部访问 |
访问控制示例
<?php
class AccessExample {
public $publicVar = "公有属性";
protected $protectedVar = "受保护属性";
private $privateVar = "私有属性";
public function getPrivateVar() {
return $this->privateVar; // 在类内部可以访问私有属性
}
protected function protectedMethod() {
return "受保护的方法";
}
private function privateMethod() {
return "私有的方法";
}
}
$obj = new AccessExample();
echo $obj->publicVar; // 可以访问
// echo $obj->protectedVar; // 错误:不能访问受保护属性
// echo $obj->privateVar; // 错误:不能访问私有属性
echo $obj->getPrivateVar(); // 通过公有方法访问私有属性
?>
继承
继承允许一个类(子类)继承另一个类(父类)的属性和方法。
继承示例
<?php
// 父类
class Animal {
protected $name;
protected $sound;
public function __construct($name, $sound) {
$this->name = $name;
$this->sound = $sound;
}
public function speak() {
return $this->name . "说:" . $this->sound;
}
public function eat() {
return $this->name . "正在吃东西";
}
}
// 子类
class Dog extends Animal {
private $breed;
public function __construct($name, $breed) {
parent::__construct($name, "汪汪");
$this->breed = $breed;
}
// 重写父类方法
public function speak() {
return $this->name . "(" . $this->breed . ")大声叫:" . $this->sound . "!";
}
// 子类特有的方法
public function fetch() {
return $this->name . "正在捡球";
}
}
// 使用子类
$dog = new Dog("旺财", "金毛");
echo $dog->speak(); // 输出:旺财(金毛)大声叫:汪汪!
echo "<br>";
echo $dog->eat(); // 继承自父类
echo "<br>";
echo $dog->fetch(); // 子类特有的方法
?>
final关键字
使用final关键字可以防止类被继承或方法被重写。
final关键字示例
<?php
final class FinalClass {
// 这个类不能被继承
}
class ParentClass {
final public function finalMethod() {
return "这个方法不能被子类重写";
}
}
class ChildClass extends ParentClass {
// 尝试重写final方法会导致错误
// public function finalMethod() { }
}
?>
静态属性和方法
静态属性和方法属于类本身,而不是类的实例。
静态成员示例
<?php
class Counter {
public static $count = 0;
public function __construct() {
self::$count++;
}
public static function getCount() {
return self::$count;
}
public static function resetCount() {
self::$count = 0;
}
}
// 使用静态属性和方法
$obj1 = new Counter();
$obj2 = new Counter();
$obj3 = new Counter();
echo "创建的对象数量:" . Counter::getCount(); // 输出:3
echo "<br>";
echo "计数器值:" . Counter::$count; // 输出:3
Counter::resetCount();
echo "<br>重置后计数器值:" . Counter::getCount(); // 输出:0
?>
接口和抽象类
接口
接口定义了一个类必须实现的方法,但不提供具体实现。
接口示例
<?php
// 定义接口
interface Vehicle {
public function start();
public function stop();
public function getInfo();
}
// 实现接口
class Car implements Vehicle {
public function start() {
return "汽车启动";
}
public function stop() {
return "汽车停止";
}
public function getInfo() {
return "这是一辆汽车";
}
}
class Bicycle implements Vehicle {
public function start() {
return "自行车开始骑行";
}
public function stop() {
return "自行车停止";
}
public function getInfo() {
return "这是一辆自行车";
}
}
$car = new Car();
echo $car->start();
echo "<br>";
$bicycle = new Bicycle();
echo $bicycle->start();
?>
抽象类
抽象类不能实例化,只能被继承,可以包含抽象方法和具体方法。
抽象类示例
<?php
// 定义抽象类
abstract class Shape {
protected $name;
public function __construct($name) {
$this->name = $name;
}
// 抽象方法,必须在子类中实现
abstract public function area();
abstract public function perimeter();
// 具体方法
public function getName() {
return $this->name;
}
}
// 实现抽象类
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($width, $height) {
parent::__construct("矩形");
$this->width = $width;
$this->height = $height;
}
public function area() {
return $this->width * $this->height;
}
public function perimeter() {
return 2 * ($this->width + $this->height);
}
}
class Circle extends Shape {
private $radius;
public function __construct($radius) {
parent::__construct("圆形");
$this->radius = $radius;
}
public function area() {
return pi() * pow($this->radius, 2);
}
public function perimeter() {
return 2 * pi() * $this->radius;
}
}
$rect = new Rectangle(5, 3);
echo $rect->getName() . "面积:" . $rect->area();
echo "<br>";
echo $rect->getName() . "周长:" . $rect->perimeter();
echo "<br><br>";
$circle = new Circle(4);
echo $circle->getName() . "面积:" . round($circle->area(), 2);
echo "<br>";
echo $circle->getName() . "周长:" . round($circle->perimeter(), 2);
?>
魔术方法
PHP提供了一系列以双下划线开头的魔术方法,它们在特定情况下自动调用。
常用魔术方法
<?php
class MagicMethods {
private $data = [];
// __get 在访问不可访问属性时调用
public function __get($name) {
return isset($this->data[$name]) ? $this->data[$name] : null;
}
// __set 在给不可访问属性赋值时调用
public function __set($name, $value) {
$this->data[$name] = $value;
}
// __toString 在对象被当作字符串时调用
public function __toString() {
return "这是一个MagicMethods对象";
}
// __call 在调用不可访问方法时调用
public function __call($name, $arguments) {
return "调用了不存在的方法:$name,参数:" . implode(", ", $arguments);
}
// __callStatic 在静态调用不可访问方法时调用
public static function __callStatic($name, $arguments) {
return "静态调用了不存在的方法:$name";
}
// __isset 在对不可访问属性调用isset()或empty()时调用
public function __isset($name) {
return isset($this->data[$name]);
}
// __unset 在对不可访问属性调用unset()时调用
public function __unset($name) {
unset($this->data[$name]);
}
}
$obj = new MagicMethods();
$obj->name = "测试"; // 调用 __set
echo $obj->name; // 调用 __get
echo "<br>";
echo $obj; // 调用 __toString
echo "<br>";
echo $obj->undefinedMethod("参数1", "参数2"); // 调用 __call
echo "<br>";
echo MagicMethods::undefinedStaticMethod(); // 调用 __callStatic
echo "<br>";
echo "name属性存在吗? " . (isset($obj->name) ? "是" : "否"); // 调用 __isset
?>
命名空间
命名空间用于解决命名冲突,组织和管理代码。
命名空间示例
<?php
// 文件: utils/Validator.php
namespace Utils;
class Validator {
public static function validateEmail($email) {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
}
// 文件: services/UserService.php
namespace Services;
class UserService {
public function createUser($email) {
// 使用完全限定名称
if (\Utils\Validator::validateEmail($email)) {
return "用户创建成功";
}
return "邮箱格式无效";
}
}
// 使用命名空间
$userService = new \Services\UserService();
echo $userService->createUser("test@example.com");
?>
Trait特性
Trait是PHP 5.4引入的代码复用机制,可以在不同类中复用方法。
Trait示例
<?php
trait Logger {
public function log($message) {
$timestamp = date("Y-m-d H:i:s");
echo "[$timestamp] $message<br>";
}
}
trait Timestamp {
public function getTimestamp() {
return time();
}
}
class User {
use Logger, Timestamp;
public function register() {
$this->log("用户注册成功");
return "注册时间: " . $this->getTimestamp();
}
}
class Product {
use Logger;
public function create() {
$this->log("产品创建成功");
return "产品已创建";
}
}
$user = new User();
echo $user->register();
echo "<br>";
$product = new Product();
echo $product->create();
?>
面向对象设计原则
编写高质量面向对象代码的一些指导原则:
SOLID原则
- 单一职责原则 (SRP): 一个类应该只有一个引起变化的原因
- 开放封闭原则 (OCP): 对扩展开放,对修改封闭
- 里氏替换原则 (LSP): 子类应该能够替换父类
- 接口隔离原则 (ISP): 使用多个专门的接口比使用单一的总接口好
- 依赖倒置原则 (DIP): 依赖于抽象而不是具体实现
依赖注入示例
<?php
interface LoggerInterface {
public function log($message);
}
class FileLogger implements LoggerInterface {
public function log($message) {
// 记录到文件
echo "记录到文件: $message<br>";
}
}
class DatabaseLogger implements LoggerInterface {
public function log($message) {
// 记录到数据库
echo "记录到数据库: $message<br>";
}
}
class UserService {
private $logger;
// 依赖注入
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function register($username) {
// 注册逻辑...
$this->logger->log("用户 $username 注册成功");
return "用户注册成功";
}
}
// 使用不同的日志实现
$fileLogger = new FileLogger();
$userService = new UserService($fileLogger);
echo $userService->register("张三");
$dbLogger = new DatabaseLogger();
$userService2 = new UserService($dbLogger);
echo $userService2->register("李四");
?>
实践练习
创建一个完整的面向对象PHP应用程序,实现以下功能:
- 设计一个简单的电子商务系统
- 创建Product类、User类、Order类等
- 使用继承创建不同的产品类别
- 使用接口定义通用行为
- 使用命名空间组织代码
- 实现依赖注入
- 使用Trait复用代码
- 应用SOLID原则
提示: 可以从简单的类开始,逐步添加功能,确保每个类都有明确的职责。