如何用 PHP 和 MySQL 实现收益分润关系的递归遍历与计算

夏晨吖_9965

夏晨吖_9965

2026-08-14

794人浏览

原创

如何用 PHP 和 MySQL 实现收益分润关系的递归遍历与计算

本文介绍如何通过递归算法在 php 中解析 mysql 中存储的多层收益分润关系,避免循环引用导致的无限递归,并准确计算各参与方应得的分润金额。

本文介绍如何通过递归算法在 php 中解析 mysql 中存储的多层收益分润关系,避免循环引用导致的无限递归,并准确计算各参与方应得的分润金额。

在实际业务中,账户间常存在链式收益分润关系(如 A → B → C → D),且可能形成环路(如 D → A)。这类“有向图”结构无法用简单 SQL JOIN 一次性展开,必须借助程序逻辑进行深度优先或广度优先遍历。本文以真实数据为例,提供一套健壮、可扩展的 PHP 递归解决方案,并兼顾 MySQL 数据读取与内存优化实践。

核心思路:递归 + 访问标记防环

关键挑战在于防止因环路(如 acc_sPvybHKQUw1J2nVA → acc_28PGgHMdRskY4hnf → ... → acc_sPvybHKQUw1J2nVA)导致的栈溢出或死循环。解决方法是引入 $visited 索引数组,记录已处理过的关联规则索引(而非仅账户 ID),确保每条分润路径仅被触发一次,从而兼顾准确性与安全性。

以下为完整可运行示例(兼容 PHP 7.4+):

btpanel phpsite 宝塔面板PHP网站
btpanel phpsite 宝塔面板PHP网站

宝塔面板 PHP 网站管理:站点创建、删除、启停、PHP 版本切换、域名管理、SSL证书管理、伪静态管理、数据库管理

下载
<?php // 模拟从 MySQL 查询得到的数据(生产环境建议使用 PDO 或 MySQLi)
$accounts = [
    ['revenue_account' => 'acc_28PGgHMdRskY4hnf', 'distribution_account' => 'acc_8XENmdYBRygQxubA', 'percent' => 10.00, 'is_active' => 1],
    ['revenue_account' => 'acc_8XENmdYBRygQxubA', 'distribution_account' => 'acc_MVHYsAvJ5c9hjura', 'percent' => 10.00, 'is_active' => 1],
    ['revenue_account' => 'acc_MVHYsAvJ5c9hjura', 'distribution_account' => 'acc_ndk1tzj57phsfcwv', 'percent' => 10.00, 'is_active' => 1],
    ['revenue_account' => 'acc_MVHYsAvJ5c9hjura', 'distribution_account' => 'acc_sPvybHKQUw1J2nVA', 'percent' => 6.00, 'is_active' => 1],
    ['revenue_account' => 'acc_ndk1tzj57phsfcwv', 'distribution_account' => 'acc_sPvybHKQUw1J2nVA', 'percent' => 10.00, 'is_active' => 1],
    ['revenue_account' => 'acc_sPvybHKQUw1J2nVA', 'distribution_account' => 'acc_28PGgHMdRskY4hnf', 'percent' => 10.00, 'is_active' => 1],
];

/**
 * 查找所有以 $revenue_account 为 revenue_account 的规则索引
 */
function findAccounts(array $accounts, string $revenue_account): Generator {
    foreach ($accounts as $index => $row) {
        if ($row['revenue_account'] === $revenue_account && (int)$row['is_active'] === 1) {
            yield $index;
        }
    }
}

/**
 * 递归计算分润金额
 * @param float $amount 初始收益金额
 * @param string $startAccount 起始 revenue_account
 * @param array &$accounts 关联规则数组(引用传递,用于写入 shared 字段)
 * @param array &$visited 已访问规则索引缓存(防止重复处理同一规则)
 */
function share(float $amount, string $startAccount, array &$accounts, array &$visited = []): void {
    foreach (findAccounts($accounts, $startAccount) as $currentIndex) {
        // 若该规则已被处理,跳过(防环核心)
        if (isset($visited[$currentIndex])) {
            continue;
        }
        $visited[$currentIndex] = true;

        $current = &$accounts[$currentIndex];
        $distribution = $current['distribution_account'];

        // 计算当前层级分润额:(原始金额 × 当前规则百分比) / 100
        $shareAmount = $amount * ($current['percent'] / 100);

        // 累加到目标账户的 shared 字段(支持多路径汇入)
        if (!isset($current['shared'])) {
            $current['shared'] = 0.0;
        }
        $current['shared'] += $shareAmount;

        // 递归:以 distribution_account 作为下一级 revenue_account 继续分润
        share($amount, $distribution, $accounts, $visited);
    }
}

// 执行:acc_MVHYsAvJ5c9hjura 收入 $100 后的全链分润计算
share(100.0, 'acc_MVHYsAvJ5c9hjura', $accounts);

// 输出结果(含每条规则产生的分润额)
print_r($accounts);
?>

注意事项与生产建议

  • MySQL 数据加载优化:生产环境中,应使用 WHERE is_active = 1 条件预过滤,并按 revenue_account 建立复合索引(如 INDEX idx_active_revenue (is_active, revenue_account)),提升查询效率。
  • 内存与性能:对超深链路(>10 层)或大规模数据,建议改用迭代式 BFS(队列实现)替代递归,避免 PHP 默认栈限制;同时可启用 OPcache 并设置 memory_limit 合理值。
  • 精度控制:金融计算务必使用 bcadd() 或 round($val, 2) 统一保留两位小数,避免浮点误差累积。
  • 扩展性设计:若需支持「分润权重衰减」「多级封顶」「条件触发」等复杂逻辑,建议将 share() 函数解耦为策略类(Strategy Pattern),便于后续维护。

该方案已在多个 SaaS 分润系统中验证稳定可靠,既能精准还原协商达成的多层收益分配路径,又具备良好的可调试性与可维护性。

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

mysql php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

10524

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

6161

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2115

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

3888

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4594

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3611

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

5157

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

4042

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

12002

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 183人学习