构造函数和析构函数
构造函数和析构函数是PHP面向对象编程中两个非常重要的特殊方法。它们分别在对象创建和销毁时自动调用,为我们提供了初始化资源和清理资源的机会。
学习目标
完成本节学习后,你将能够:
- 理解构造函数的作用和使用场景
- 掌握构造函数的定义和使用方法
- 学会通过构造函数实现依赖注入
- 理解析构函数的作用和执行时机
- 掌握资源管理的基本技巧
- 了解对象生命周期的完整过程
构造函数(Constructor)
什么是构造函数
构造函数是在创建对象时自动调用的特殊方法。它的主要作用是:
- 初始化对象属性:为对象的属性设置初始值
- 分配资源:如数据库连接、文件句柄等
- 执行验证:确保传入的参数符合要求
- 建立对象状态:确保对象处于可用状态
构造函数的语法
<?php
class MyClass {
// PHP 5.3.3+ 可以使用类名作为构造函数(不推荐)
// public function MyClass() {
// echo "这是旧式的构造函数";
// }
// 现代推荐的构造函数语法
public function __construct() {
echo "构造函数被调用\n";
}
}
?>
基本构造函数示例
<?php
class User {
private $id;
private $username;
private $email;
private $createdAt;
// 基本构造函数
public function __construct() {
echo "创建了一个新用户对象\n";
$this->id = null;
$this->username = 'guest';
$this->email = '';
$this->createdAt = date('Y-m-d H:i:s');
}
// 获取器方法
public function getUsername() {
return $this->username;
}
public function getEmail() {
return $this->email;
}
public function getCreatedAt() {
return $this->createdAt;
}
}
// 使用基本构造函数
echo "=== 基本构造函数示例 ===\n";
$user1 = new User(); // 输出:创建了一个新用户对象
echo "用户名:{$user1->getUsername()}\n";
echo "创建时间:{$user1->getCreatedAt()}\n";
?>
带参数的构造函数
<?php
class Product {
private $id;
private $name;
private $price;
private $category;
private $inStock;
// 带参数的构造函数
public function __construct($name, $price, $category = '默认分类') {
echo "创建产品:$name\n";
$this->id = uniqid('product_');
$this->name = $this->validateName($name);
$this->price = $this->validatePrice($price);
$this->category = $category;
$this->inStock = true;
}
// 验证产品名称
private function validateName($name) {
if (empty($name)) {
throw new Exception("产品名称不能为空");
}
if (strlen($name) > 100) {
throw new Exception("产品名称过长");
}
return trim($name);
}
// 验证价格
private function validatePrice($price) {
if (!is_numeric($price) || $price < 0) {
throw new Exception("价格必须是非负数");
}
return (float)$price;
}
// 获取器方法
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
public function getPrice() {
return $this->price;
}
public function getCategory() {
return $this->category;
}
public function isInStock() {
return $this->inStock;
}
// 设置库存状态
public function setInStock($inStock) {
$this->inStock = (bool)$inStock;
}
// 获取产品信息
public function getInfo() {
$status = $this->inStock ? "有货" : "缺货";
return sprintf(
"产品:%s | 价格:¥%.2f | 分类:%s | 状态:%s",
$this->name,
$this->price,
$this->category,
$status
);
}
}
// 使用带参数的构造函数
echo "=== 带参数的构造函数示例 ===\n";
try {
$product1 = new Product("笔记本电脑", 5999.99, "电子产品");
$product2 = new Product("办公椅", 299.50); // 使用默认分类
$product3 = new Product("咖啡杯", 15.80);
echo $product1->getInfo() . "\n";
echo $product2->getInfo() . "\n";
echo $product3->getInfo() . "\n";
} catch (Exception $e) {
echo "错误:" . $e->getMessage() . "\n";
}
?>
构造函数中的复杂初始化
<?php
class DatabaseConnection {
private $connection;
private $host;
private $database;
private $isConnected = false;
// 复杂的构造函数初始化
public function __construct($host, $database, $username, $password) {
echo "正在初始化数据库连接...\n";
$this->host = $this->validateHost($host);
$this->database = $this->validateDatabase($database);
try {
$this->connection = $this->createConnection($host, $database, $username, $password);
$this->isConnected = true;
echo "数据库连接成功!\n";
// 执行初始化设置
$this->initializeDatabase();
} catch (Exception $e) {
echo "数据库连接失败:" . $e->getMessage() . "\n";
$this->isConnected = false;
throw $e; // 重新抛出异常
}
}
private function validateHost($host) {
if (empty($host)) {
throw new Exception("数据库主机不能为空");
}
return $host;
}
private function validateDatabase($database) {
if (empty($database)) {
throw new Exception("数据库名称不能为空");
}
return $database;
}
private function createConnection($host, $database, $username, $password) {
// 模拟数据库连接创建
echo "创建连接到 $host/$database\n";
// 在实际应用中,这里会使用 PDO 或 mysqli
// 这里我们模拟连接过程
if ($username === 'wrong' || $password === 'wrong') {
throw new Exception("认证失败");
}
return "模拟数据库连接对象";
}
private function initializeDatabase() {
echo "执行数据库初始化设置...\n";
// 设置字符编码
// 设置时区
// 创建必要的表等
echo "数据库初始化完成\n";
}
public function isConnected() {
return $this->isConnected;
}
public function getConnection() {
return $this->connection;
}
public function getHost() {
return $this->host;
}
public function getDatabase() {
return $this->database;
}
}
// 使用复杂初始化的构造函数
echo "=== 复杂初始化构造函数示例 ===\n";
try {
// 正常连接
$db1 = new DatabaseConnection("localhost", "myapp", "user", "pass");
echo "数据库状态:" . ($db1->isConnected() ? "已连接" : "未连接") . "\n";
echo "连接信息:{$db1->getHost()}/{$db1->getDatabase()}\n\n";
// 错误连接
echo "尝试错误的连接...\n";
$db2 = new DatabaseConnection("localhost", "myapp", "wrong", "pass");
} catch (Exception $e) {
echo "捕获到异常:" . $e->getMessage() . "\n";
}
?>
依赖注入(Dependency Injection)
依赖注入是构造函数的重要用途之一,它让代码更加灵活和可测试。
<?php
class Logger {
private $logFile;
public function __construct($logFile = 'app.log') {
$this->logFile = $logFile;
echo "Logger 初始化,日志文件:$logFile\n";
}
public function log($message) {
$timestamp = date('Y-m-d H:i:s');
$logMessage = "[$timestamp] $message\n";
echo "记录日志:$logMessage";
// 在实际应用中会写入文件
// file_put_contents($this->logFile, $logMessage, FILE_APPEND);
}
}
class EmailService {
private $smtpServer;
private $logger;
// 依赖注入构造函数
public function __construct($smtpServer, Logger $logger) {
$this->smtpServer = $smtpServer;
$this->logger = $logger;
echo "EmailService 初始化,SMTP服务器:$smtpServer\n";
$this->logger->log("EmailService 已启动");
}
public function sendEmail($to, $subject, $message) {
$this->logger->log("准备发送邮件到: $to");
// 模拟邮件发送
echo "发送邮件到:$to\n";
echo "主题:$subject\n";
echo "内容:$message\n";
$this->logger->log("邮件发送成功到: $to");
return true;
}
public function getSmtpServer() {
return $this->smtpServer;
}
}
class UserService {
private $emailService;
private $logger;
// 多依赖注入
public function __construct(EmailService $emailService, Logger $logger) {
$this->emailService = $emailService;
$this->logger = $logger;
echo "UserService 初始化完成\n";
$this->logger->log("UserService 已启动");
}
public function registerUser($email, $username) {
$this->logger->log("注册新用户: $username ($email)");
// 模拟用户注册
echo "用户 $username 注册成功\n";
// 发送欢迎邮件
$this->emailService->sendEmail(
$email,
"欢迎注册",
"欢迎 $username 加入我们的平台!"
);
return true;
}
}
// 使用依赖注入
echo "=== 依赖注入示例 ===\n";
// 1. 创建基础服务
$logger = new Logger('user_service.log');
$emailService = new EmailService('smtp.example.com', $logger);
// 2. 将依赖注入到高级服务中
$userService = new UserService($emailService, $logger);
// 3. 使用服务
echo "\n=== 执行用户注册 ===\n";
$userService->registerUser('alice@example.com', 'Alice');
?>
构造函数重载(PHP不支持,但可通过默认参数和可选参数模拟)
<?php
class Order {
private $orderId;
private $customerName;
private $items;
private $totalAmount;
private $orderDate;
private $shippingAddress;
private $discountCode;
// 使用可选参数模拟重载
public function __construct(
$customerName,
$items = [],
$totalAmount = 0.0,
$shippingAddress = null,
$discountCode = null
) {
$this->orderId = uniqid('order_');
$this->customerName = $customerName;
$this->items = $items;
$this->totalAmount = $totalAmount;
$this->orderDate = date('Y-m-d H:i:s');
$this->shippingAddress = $shippingAddress ?: $customerName . ' 的默认地址';
$this->discountCode = $discountCode;
echo "创建订单 #$this->orderId\n";
$this->applyDiscount();
}
private function applyDiscount() {
if ($this->discountCode === 'SAVE10') {
$this->totalAmount *= 0.9;
echo "应用10%折扣\n";
} elseif ($this->discountCode === 'SAVE20') {
$this->totalAmount *= 0.8;
echo "应用20%折扣\n";
}
}
public function getInfo() {
return sprintf(
"订单 #%s | 客户:%s | 金额:¥%.2f | 地址:%s",
substr($this->orderId, -8),
$this->customerName,
$this->totalAmount,
$this->shippingAddress
);
}
}
// 模拟不同的构造方式
echo "=== 构造函数参数重载示例 ===\n";
// 方式1:最简单的订单
$order1 = new Order("张三");
echo $order1->getInfo() . "\n\n";
// 方式2:带商品的订单
$items = ["笔记本", "鼠标", "键盘"];
$order2 = new Order("李四", $items, 1500.00);
echo $order2->getInfo() . "\n\n";
// 方式3:完整的订单
$order3 = new Order(
"王五",
["手机", "充电器", "耳机"],
3999.00,
"北京市朝阳区某某街道123号",
"SAVE10"
);
echo $order3->getInfo() . "\n";
?>
析构函数(Destructor)
什么是析构函数
析构函数是在对象被销毁时自动调用的特殊方法。它的主要作用是:
- 清理资源:关闭文件句柄、数据库连接等
- 释放内存:清理大对象的内存
- 保存状态:保存对象的最终状态
- 执行清理逻辑:确保对象完全销毁前的清理工作
析构函数的语法
<?php
class MyClass {
private $resource;
public function __construct() {
echo "构造函数:分配资源\n";
$this->resource = "模拟资源";
}
// 析构函数
public function __destruct() {
echo "析构函数:清理资源\n";
$this->resource = null;
}
}
?>
基本析构函数示例
<?php
class TempFile {
private $filename;
private $handle;
private $content;
public function __construct($filename, $content = '') {
echo "创建临时文件:$filename\n";
$this->filename = $filename;
$this->content = $content;
// 模拟文件创建
$this->handle = fopen("php://memory", "r+"); // 使用内存文件
fwrite($this->handle, $content);
rewind($this->handle);
echo "文件句柄已创建\n";
}
public function write($data) {
$this->content .= $data;
fwrite($this->handle, $data);
echo "写入数据:$data\n";
}
public function read() {
rewind($this->handle);
$content = stream_get_contents($this->handle);
echo "读取文件内容:$content\n";
return $content;
}
public function getSize() {
return strlen($this->content);
}
public function __destruct() {
echo "销毁临时文件:$this->filename\n";
// 关闭文件句柄
if (is_resource($this->handle)) {
fclose($this->handle);
echo "文件句柄已关闭\n";
}
// 在实际应用中,这里会删除临时文件
// unlink($this->filename);
echo "临时文件清理完成\n";
}
}
// 使用析构函数
echo "=== 基本析构函数示例 ===\n";
function processTempFile() {
echo "进入函数 processTempFile\n";
$tempFile = new TempFile("temp_data.txt", "初始内容\n");
$tempFile->write("添加的内容\n");
$tempFile->read();
echo "文件大小:{$tempFile->getSize()} 字节\n";
echo "退出函数 processTempFile\n";
// $tempFile 对象在这里会被销毁,自动调用 __destruct()
}
processTempFile();
echo "函数执行结束\n\n";
// 直接创建和销毁对象
echo "=== 直接创建对象 ===\n";
$tempFile2 = new TempFile("another_temp.txt", "另一个文件");
unset($tempFile2); // 手动触发析构函数
echo "对象已被手动销毁\n";
?>
数据库连接的析构清理
<?php
class DatabaseConnection {
private $connectionId;
private $isConnected = false;
private $queryCount = 0;
public function __construct($database) {
$this->connectionId = uniqid('db_');
echo "建立数据库连接到:$database (ID: $this->connectionId)\n";
// 模拟连接建立
$this->isConnected = true;
echo "数据库连接已建立\n";
}
public function query($sql) {
if (!$this->isConnected) {
throw new Exception("数据库未连接");
}
$this->queryCount++;
echo "执行查询 #$this->queryCount: $sql\n";
// 模拟查询执行
return "查询结果";
}
public function getConnectionId() {
return $this->connectionId;
}
public function getQueryCount() {
return $this->queryCount;
}
public function __destruct() {
echo "\n开始清理数据库连接 (ID: $this->connectionId)\n";
if ($this->isConnected) {
echo "关闭数据库连接...\n";
$this->isConnected = false;
// 在实际应用中,这里会关闭实际的数据库连接
// $this->connection->close();
echo "数据库连接已关闭\n";
echo "总共执行了 $this->queryCount 个查询\n";
}
echo "数据库连接清理完成\n";
}
}
// 使用数据库连接类
echo "=== 数据库连接析构示例 ===\n";
function performDatabaseOperations() {
echo "=== 开始数据库操作 ===\n";
$db = new DatabaseConnection("myapp_db");
echo "\n执行一些查询...\n";
$db->query("SELECT * FROM users");
$db->query("SELECT * FROM products WHERE category = 'electronics'");
$db->query("INSERT INTO orders (user_id, total) VALUES (1, 100.00)");
echo "\n数据库操作完成,函数即将结束\n";
// $db 对象在函数结束时会被销毁
}
performDatabaseOperations();
echo "\n函数已结束,数据库连接应该已被清理\n";
?>
对象引用与析构时机
<?php
class ResourceTracker {
private $name;
private static $activeObjects = [];
public function __construct($name) {
$this->name = $name;
self::$activeObjects[] = $this;
echo "创建资源:$name\n";
$this->showActiveCount();
}
public function getName() {
return $this->name;
}
public static function showActiveCount() {
echo "当前活跃对象数:" . count(self::$activeObjects) . "\n";
}
public function __destruct() {
echo "销毁资源:$this->name\n";
// 从活跃对象列表中移除
$key = array_search($this, self::$activeObjects, true);
if ($key !== false) {
unset(self::$activeObjects[$key]);
self::$activeObjects = array_values(self::$activeObjects);
}
$this->showActiveCount();
}
}
// 演示不同的对象销毁时机
echo "=== 对象引用与析构时机示例 ===\n";
// 1. 普通变量
echo "\n1. 普通变量作用域:\n";
{
$obj1 = new ResourceTracker("对象1");
$obj2 = new ResourceTracker("对象2");
echo "离开代码块,对象将被销毁\n";
}
echo "已离开代码块\n\n";
// 2. 引用情况
echo "2. 对象引用:\n";
$obj3 = new ResourceTracker("对象3");
$reference = $obj3; // 引用
echo "复制引用\n";
$anotherRef = $obj3;
echo "unset 第一个变量\n";
unset($obj3);
ResourceTracker::showActiveCount();
echo "unset 第二个变量\n";
unset($reference);
ResourceTracker::showActiveCount();
echo "unset 最后一个变量\n";
unset($anotherRef);
echo "对象应该已被销毁\n\n";
// 3. 数组中的对象
echo "3. 数组中的对象:\n";
$objects = [];
$objects[] = new ResourceTracker("数组对象1");
$objects[] = new ResourceTracker("数组对象2");
$objects[] = new ResourceTracker("数组对象3");
echo "清空数组\n";
$objects = []; // 这会触发所有对象的析构函数
echo "数组已清空\n\n";
// 4. 函数参数传递
echo "4. 函数参数传递:\n";
function processObject($obj) {
echo "函数内处理对象:{$obj->getName()}\n";
echo "即将离开函数\n";
}
$obj4 = new ResourceTracker("函数对象");
processObject($obj4);
echo "函数结束,对象应该还存在\n";
echo "手动销毁对象\n";
unset($obj4);
?>
复杂的资源管理
<?php
class FileProcessor {
private $inputFile;
private $outputFile;
private $tempFiles = [];
private $processingSteps = [];
public function __construct($inputFile, $outputFile) {
echo "初始化文件处理器\n";
echo "输入文件:$inputFile\n";
echo "输出文件:$outputFile\n";
$this->inputFile = $inputFile;
$this->outputFile = $outputFile;
// 模拟文件打开
$this->openFiles();
$this->logStep("初始化完成");
}
private function openFiles() {
echo "打开输入文件:{$this->inputFile}\n";
echo "创建输出文件:{$this->outputFile}\n";
// 在实际应用中,这里会使用 fopen()
$this->logStep("文件已打开");
}
public function processData($data) {
$this->logStep("开始处理数据");
// 创建临时文件
$tempFile = $this->createTempFile($data);
// 处理数据
$processedData = $this->transformData($data);
// 写入输出
$this->writeOutput($processedData);
// 清理临时文件
$this->cleanupTempFile($tempFile);
$this->logStep("数据处理完成");
return $processedData;
}
private function createTempFile($data) {
$tempFile = "temp_" . uniqid() . ".tmp";
$this->tempFiles[] = $tempFile;
echo "创建临时文件:$tempFile\n";
// 在实际应用中,这里会写入实际文件
$this->logStep("临时文件已创建:$tempFile");
return $tempFile;
}
private function transformData($data) {
echo "转换数据:$data\n";
// 模拟数据处理
$transformed = strtoupper($data) . " [已处理]";
$this->logStep("数据转换完成");
return $transformed;
}
private function writeOutput($data) {
echo "写入输出文件:{$this->outputFile}\n";
echo "内容:$data\n";
$this->logStep("数据已写入输出文件");
}
private function cleanupTempFile($tempFile) {
echo "清理临时文件:$tempFile\n";
// 从列表中移除
$key = array_search($tempFile, $this->tempFiles);
if ($key !== false) {
unset($this->tempFiles[$key]);
$this->tempFiles = array_values($this->tempFiles);
}
// 在实际应用中,这里会删除实际文件
$this->logStep("临时文件已清理:$tempFile");
}
private function logStep($step) {
$timestamp = date('H:i:s');
$this->processingSteps[] = "[$timestamp] $step";
echo " - $step\n";
}
public function getProcessingLog() {
return $this->processingSteps;
}
public function __destruct() {
echo "\n=== 析构函数:清理文件处理器 ===\n";
// 关闭文件
echo "关闭输入文件:{$this->inputFile}\n";
echo "关闭输出文件:{$this->outputFile}\n";
// 清理所有剩余的临时文件
if (!empty($this->tempFiles)) {
echo "清理剩余的临时文件:\n";
foreach ($this->tempFiles as $tempFile) {
echo " - 删除 $tempFile\n";
// unlink($tempFile);
}
$this->tempFiles = [];
}
// 显示处理日志
if (!empty($this->processingSteps)) {
echo "\n处理步骤总结:\n";
foreach ($this->processingSteps as $i => $step) {
echo " " . ($i + 1) . ". $step\n";
}
}
echo "文件处理器清理完成\n";
}
}
// 使用复杂的资源管理
echo "=== 复杂资源管理示例 ===\n";
function processUserData() {
$processor = new FileProcessor("input.txt", "output.txt");
echo "\n开始处理用户数据...\n";
$processor->processData("Hello World");
$processor->processData("PHP Programming");
$processor->processData("File Processing");
echo "\n用户数据处理完成\n";
// $processor 在函数结束时会被销毁
}
processUserData();
echo "函数执行结束,所有资源应该已被清理\n";
?>
实际应用示例
配置管理器
<?php
class ConfigManager {
private $configFile;
private $config = [];
private $isModified = false;
private $autoSave;
public function __construct($configFile, $autoSave = true) {
echo "初始化配置管理器\n";
echo "配置文件:$configFile\n";
echo "自动保存:" . ($autoSave ? "启用" : "禁用") . "\n";
$this->configFile = $configFile;
$this->autoSave = $autoSave;
$this->loadConfig();
}
private function loadConfig() {
echo "加载配置文件...\n";
// 在实际应用中,这里会读取JSON、INI等配置文件
// 模拟配置加载
$this->config = [
'database' => [
'host' => 'localhost',
'port' => 3306,
'name' => 'myapp'
],
'app' => [
'debug' => false,
'timezone' => 'Asia/Shanghai'
]
];
echo "配置加载完成,共 " . count($this->config, COUNT_RECURSIVE) . " 个配置项\n";
}
public function get($key, $default = null) {
$keys = explode('.', $key);
$value = $this->config;
foreach ($keys as $k) {
if (isset($value[$k])) {
$value = $value[$k];
} else {
return $default;
}
}
return $value;
}
public function set($key, $value) {
echo "设置配置:$key = " . (is_bool($value) ? ($value ? 'true' : 'false') : $value) . "\n";
$keys = explode('.', $key);
$config = &$this->config;
for ($i = 0; $i < count($keys) - 1; $i++) {
if (!isset($config[$keys[$i]])) {
$config[$keys[$i]] = [];
}
$config = &$config[$keys[$i]];
}
$config[$keys[count($keys) - 1]] = $value;
$this->isModified = true;
}
public function has($key) {
return $this->get($key) !== null;
}
public function remove($key) {
if ($this->has($key)) {
echo "删除配置:$key\n";
// 实际实现中需要处理嵌套键
$this->isModified = true;
}
}
public function save() {
if (!$this->isModified) {
echo "配置未修改,无需保存\n";
return;
}
echo "保存配置到文件:{$this->configFile}\n";
// 在实际应用中,这里会写入文件
$this->isModified = false;
echo "配置保存成功\n";
}
public function getConfig() {
return $this->config;
}
public function __destruct() {
echo "\n=== 配置管理器析构 ===\n";
if ($this->autoSave && $this->isModified) {
echo "检测到配置修改,自动保存...\n";
$this->save();
} else {
echo "配置管理器关闭(修改的配置:" . ($this->isModified ? "是" : "否") . ")\n";
}
}
}
// 使用配置管理器
echo "=== 配置管理器示例 ===\n";
function configureApp() {
$config = new ConfigManager("app.conf");
echo "\n读取配置:\n";
echo "数据库主机:" . $config->get('database.host') . "\n";
echo "调试模式:" . ($config->get('app.debug', false) ? '开启' : '关闭') . "\n";
echo "\n修改配置:\n";
$config->set('app.debug', true);
$config->set('database.charset', 'utf8mb4');
echo "\n读取新配置:\n";
echo "调试模式:" . ($config->get('app.debug') ? '开启' : '关闭') . "\n";
echo "数据库字符集:" . $config->get('database.charset', '未设置') . "\n";
// 函数结束时,由于配置被修改且启用了自动保存,会自动触发保存
}
configureApp();
echo "应用配置完成\n\n";
// 禁用自动保存的配置管理器
echo "=== 禁用自动保存 ===\n";
$config2 = new ConfigManager("user.conf", false);
$config2->set('user.name', 'Alice');
$config2->set('user.email', 'alice@example.com');
echo "手动保存配置\n";
$config2->save();
echo "手动销毁对象\n";
unset($config2);
?>
对象池模式
<?php
class ObjectPool {
private static $pools = [];
private $poolId;
private $createdObjects = [];
private $borrowedObjects = [];
private $maxSize;
public function __construct($poolId, $maxSize = 10) {
$this->poolId = $poolId;
$this->maxSize = $maxSize;
self::$pools[$poolId] = $this;
echo "创建对象池:$poolId (最大容量:$maxSize)\n";
}
public function createObject($className, ...$args) {
$objectId = uniqid();
echo "创建对象:$className (ID: $objectId)\n";
// 在实际应用中,这里会使用反射创建对象
$object = (object)[
'id' => $objectId,
'class' => $className,
'args' => $args,
'created_at' => time()
];
$this->createdObjects[$objectId] = $object;
$this->returnToPool($object);
return $objectId;
}
public function borrowObject() {
if (!empty($this->createdObjects)) {
$objectId = key($this->createdObjects);
$object = array_shift($this->createdObjects);
$this->borrowedObjects[$objectId] = $object;
echo "借用对象:$objectId\n";
return $object;
}
echo "池中无可用对象\n";
return null;
}
public function returnToPool($object) {
$objectId = $object->id;
if (isset($this->borrowedObjects[$objectId])) {
unset($this->borrowedObjects[$objectId]);
}
if (count($this->createdObjects) < $this->maxSize) {
$this->createdObjects[$objectId] = $object;
echo "对象归还到池:$objectId\n";
} else {
echo "池已满,丢弃对象:$objectId\n";
}
}
public function getPoolInfo() {
return [
'pool_id' => $this->poolId,
'pool_size' => count($this->createdObjects),
'borrowed_count' => count($this->borrowedObjects),
'max_size' => $this->maxSize
];
}
public static function getPool($poolId) {
return self::$pools[$poolId] ?? null;
}
public function __destruct() {
echo "\n=== 销毁对象池:{$this->poolId} ===\n";
// 清理所有对象
$totalObjects = count($this->createdObjects) + count($this->borrowedObjects);
echo "清理池中的对象:$totalObjects 个\n";
$this->createdObjects = [];
$this->borrowedObjects = [];
// 从全局池注册中移除
unset(self::$pools[$this->poolId]);
echo "对象池 {$this->poolId} 已销毁\n";
}
}
// 使用对象池
echo "=== 对象池示例 ===\n";
function useObjectPool() {
// 创建对象池
$pool = new ObjectPool("user_pool", 5);
echo "\n创建一些对象:\n";
$pool->createObject("User", "Alice");
$pool->createObject("User", "Bob");
$pool->createObject("User", "Charlie");
echo "\n当前池状态:\n";
$info = $pool->getPoolInfo();
echo "池大小:{$info['pool_size']}\n";
echo "借用数量:{$info['borrowed_count']}\n";
echo "\n借用和归还对象:\n";
$obj1 = $pool->borrowObject();
$obj2 = $pool->borrowObject();
$info = $pool->getPoolInfo();
echo "借用后池大小:{$info['pool_size']}\n";
$pool->returnToPool($obj1);
$info = $pool->getPoolInfo();
echo "归还后池大小:{$info['pool_size']}\n";
// 函数结束时,对象池会被销毁
}
useObjectPool();
echo "对象池使用完成\n";
?>
最佳实践和注意事项
构造函数最佳实践
- 保持简单:构造函数应该尽可能简单,只执行必要的初始化
- 避免抛出异常:尽量在构造函数中避免复杂的逻辑和可能抛出异常的操作
- 使用依赖注入:通过构造函数注入依赖,提高代码的可测试性
- 参数验证:验证传入的参数,确保对象处于有效状态
- 文档说明:清晰说明构造函数的参数和要求
<?php
// 好的构造函数设计
class UserService {
private $userRepository;
private $emailService;
private $logger;
public function __construct(
UserRepositoryInterface $userRepository,
EmailServiceInterface $emailService,
LoggerInterface $logger
) {
$this->userRepository = $userRepository;
$this->emailService = $emailService;
$this->logger = $logger;
$this->logger->info('UserService 已初始化');
}
// 其他方法...
}
?>
析构函数最佳实践
- 快速执行:析构函数应该快速执行,避免耗时操作
- 避免异常:不要在析构函数中抛出异常
- 清理资源:确保清理所有打开的资源
- 不要依赖执行时机:析构函数的执行时机不确定
- 使用引用计数:了解PHP的引用计数垃圾回收机制
<?php
// 好的析构函数设计
class DatabaseConnection {
private $connection;
private $isConnected = false;
public function __construct($config) {
$this->connection = $this->connect($config);
$this->isConnected = true;
}
public function __destruct() {
if ($this->isConnected && $this->connection) {
// 快速、安全的清理操作
$this->connection->close();
$this->isConnected = false;
}
}
// 提供显式关闭方法
public function close() {
if ($this->isConnected && $this->connection) {
$this->connection->close();
$this->isConnected = false;
}
}
}
?>
性能考虑
- 避免在析构函数中执行耗时操作
- 及时释放大对象的内存
- 考虑使用显式关闭方法而不是依赖析构函数
- 理解PHP的垃圾回收机制
总结
构造函数和析构函数是面向对象编程中的重要组成部分:
关键要点:
-
构造函数:
- 在对象创建时自动调用
- 用于初始化对象属性和分配资源
- 支持参数传递和依赖注入
- 是对象生命周期的起点
-
析构函数:
- 在对象销毁时自动调用
- 用于清理资源和释放内存
- 执行时机不确定,由垃圾回收机制决定
- 是对象生命周期的终点
-
对象生命周期:
- 创建 → 构造函数执行 → 使用 → 销毁 → 析构函数执行
- 理解引用计数和垃圾回收机制
- 合理管理对象的生命周期
-
资源管理:
- 在构造函数中分配资源
- 在析构函数中释放资源
- 遵循"谁分配,谁释放"的原则
最佳实践:
- 构造函数保持简单,只执行必要的初始化
- 析构函数快速执行,避免耗时操作
- 使用依赖注入提高代码的可测试性
- 及时清理资源,避免内存泄漏
- 理解PHP的垃圾回收机制
通过合理使用构造函数和析构函数,你可以构建更加健壮和可靠的面向对象应用程序。