前言:
在多级推广或无限极相连数据中,我们会通常使用递归来解决,但是递归深度过深会导致栈溢出,所以我们采用使用迭代(队列)来替代递归,从而实现性能更优化的查询优化。
1.使用技术SplQueue
SplQueue 是 PHP 标准库(SPL)中的一个类,用于实现队列数据结构。队列是一种先进先出(FIFO)的数据结构,适用于需要按顺序处理元素的场景。SplQueue 提供了多种方法来操作队列,如 enqueue(入队)、dequeue(出队)、isEmpty(检查队列是否为空)等。
2. 如何完美替代递归
在处理树形结构或图结构的遍历时,递归是一种常见的方法。然而,递归可能会导致栈溢出问题,尤其是在数据量较大或层级较深的情况下。SplQueue 可以通过迭代的方式完美替代递归,避免栈溢出的问题。
3.例子:使用 SplQueue 替代递归
假设我们需要遍历一个多级嵌套的用户团队结构,计算每个用户及其所有下级用户的销售数据总和。递归的方法可能会导致栈溢出,而使用 SplQueue 则可以避免这个问题。
4. 解释
-
初始化队列:
$queue = new SplQueue(); foreach ($userIds as $userId) { $queue->enqueue($userId); }
将初始用户ID列表中的每个ID加入队列。
2.迭代处理队列:
while (!$queue->isEmpty()) {
$currentUserId = $queue->dequeue(); // 统计当前用户的销售数据
$count_sum += self::countSaleData([$currentUserId]); // 查找当前用户的下级用户
$subUserIds = model('user_son')->where('aid', $currentUserId)->column('uid');
if (!empty($subUserIds)) {
foreach ($subUserIds as $subUserId) {
$queue->enqueue($subUserId);
}
}
}
- 使用
while循环不断从队列中取出用户ID进行处理。 - 调用
countSaleData方法统计当前用户的销售数据,并累加到count_sum中。 - 查找当前用户的下级用户,并将这些下级用户的ID加入队列,以便后续处理。
- return $count_sum; // 返回结果
代码总览:
1.数据库结构
CREATE TABLE `user_son` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`aid` int(10) NOT NULL COMMENT '父级',
`uid` int(10) NOT NULL COMMENT '子级',
`create_time` int(10) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户子级表';
2.代码内容
use SplQueue; // 引入 SplQueue 类
use think\Log; // 引入 Log 类
public function user() {
$userIds = model('user')->field('id')->select();
foreach($userIds as $v) {
$v['num'] = 0;
// 下级团队数据
$userArray = model('user_son')->where('aid', $v['id'])->column('uid');
$v['son_team'] = self::getAllSonTeamData($userArray, 0);
}
}
/**
* @notes 获取所有下级团队的销售数据(包括无限级别)
* @param array $userIds 用户ID列表
* @param int $count_sum 销售数据总和
* @author Milo
* @return number
*/
public static function getAllSonTeamData(array $userIds, $count_sum = 0)
{
try {
$queue = new SplQueue();
foreach ($userIds as $userId) {
$queue->enqueue($userId);
}
while (!$queue->isEmpty()) {
$currentUserId = $queue->dequeue();
// 统计当前用户的销售数据
$count_sum += self::countSaleData([$currentUserId]);
// 查找当前用户的下级用户
$subUserIds = model('user_son')->where('aid', $currentUserId)->column('uid');
if (!empty($subUserIds)) {
foreach ($subUserIds as $subUserId) {
$queue->enqueue($subUserId);
}
}
}
return $count_sum;
} catch (\Exception $e) {
// 处理异常情况
Log::error('Error in getAllSonTeamData: ' . $e->getMessage());
return 0;
}
}
/**
* @notes 数据总和
**/
public static function countSaleData(array $userArray)
{
if (empty($userArray)) return 0;
try {
// 统计销售数据总和
$count = model('user')->whereIn('id', $userArray)->sum('sale_num');
return $count;
} catch (\Exception $e) {
// 处理异常情况
Log::error('Error in countSaleData: ' . $e->getMessage());
return 0;
}
}
谢谢观看,如有不足请指出,学习进步! Tomorrow will be better