当前位置: 首页 > news >正文

复杂项目中通过使用全局变量解决问题的思维方式

最近接手了一个公司的老系统的PHP项目,里面的代码比较混乱,排查解决了一个问题,决定将这个思路记录下来,希望能帮助更多的人。

其中一部分的代码信息如下:

备注:为了避免公司的相关数据信息暴露,我对原本的代码逻辑中的一些变量和文字关键词进行了替换,但是整体的代码流程没有发生变化。因为,本篇文章我主要想分享一种解决问题的思路。

image-20250522163556422

对于以上代码,我相信稍微有个几年经验的程序员看着都会头大。没错,我看了之后也是非常头大。这段代码中存在以下几个重大问题:

  • 代码中出现了很多枚举值,例如1/0/3/1/2 ,这些枚举值大概率是数据表中的某些int类型的数据,应该放到常量里面;
  • 代码中有许多Log::info(...)的部分,直接写入日志,不方便扩展。另外,写入日志的文本也没有封装,存在大量重复的中文文本,如果需要修改,涉及到多处修改,而且,也不方便将来扩展多语言。
  • 这个方法被引用的地方太多,现在需要增加一个参数,需要修改的地方太多,稍不注意就会出现问题。

当然,这个方法还有更多其它的问题,就不一一分析了。针对这类前人留下大坑的代码,这里我主要分享两个思路,基本适用于各类大坑代码。

首先,这类已经稳定运行的代码, 别管有多乱,非必要千万别动,一不小心就会出现各种问题。但是,现在产品要求在这个业务中增加一个字段,传统的做法,可能是在方法体后面增加一个参数。例如,原本的方法体:

public function calculateCookie($goods_id, $user_id, $sys_id, $list = [])

增加参数后的方法体:

public function calculateCookie($goods_id, $user_id, $sys_id, $list = [], $new_param)

这样确实能解决问题,但是,调用这个方法的所有的上层代码都需要加一个参数。就算把这个参数设置一个默认值,也依然有风险。而且,如果这个方法的上层链路特别长,那么,需要将原始参数层层传递下来,非常麻烦,而且会有风险。比如下面这样:

image-20250522165302364

按照传统的思路,就得这么改:

image-20250522165614349

你想想,如果这个方法的上层链路像老太太的裹脚布一样,又臭又长,你稍微不留神,在哪一个环节忘记加参数,就出错了。所以,最好不要这么玩。这个时候就可以考虑定义一个全局变量,专门处理这次的改动点。

仔细梳理一下这个调用链路:

step1()->step2()->step31()->calculateCookie()

上面传统的方法是逐层传递,就像是接力赛一样,上游传递给下游。那么,换一种思路,我直接从step1()把参数传递到calculateCookie()可不可以?答案是:当然可以。而且这样做,简单高效,省去了“中间商赚差价”。

具体实现方法:

新增一个公共类文件,定义一个全局变量:

<?php
class common{public static $new_param;
}

然后在链路的最上层直接给这个全局变量赋值:

public function step1($goods_id, $user_id)
{//.... 省略更多代码//$new_param = '这是我新增的参数,需要一层一层传递下去...';common::$new_param = '这是我新增的参数,可以一步到位啦!';return $this->step2($goods_id, $user_id, 100);
}

然后在需要使用的地方,直接使用:

public function calculateCookie($goods_id, $user_id, $sys_id, $list = [])
{if (common::$new_param == 'hello') {//.....}
}

image-20250522170502014

这样一来,直接省去了中间链路的调用过程,一步直达。如果能确定这个新增的参数只在当前类的业务中使用,也可以直接定义到当前类下面:

image-20250522171122375

其实,这种思路也可以应用在需要记录和使用全局变量的场景下。比如,我需要记录一次请求生命周期的唯一ID,用来记录到日志的traceId中,就可以在接口请求的入口中设定好一个全局变量值(比如时间戳),然后在需要记录日志的地方读取这个全局变量。

另外,在我排查这个代码块的时候,发现里面的业务逻辑很长很复杂,我也没有时间和精力去分析这堆代码的背景。但是,现在有个问题,我需要复用这个代码块,并且把里面的 Log::info(...)部分的内容提取出来。这个方法是 thinkphp框架自带的一个方法,用来写入日志内容。

image-20250522171503802

我现在想把这个方法块中好几十个的写入日志的内容收集起来,并且尽可能少的改动原有的代码逻辑。我就需要使用到全局变量的思维。

首先,我要改造上面的方法,在这个class上面定义两个全局变量和set/get方法:

public  $is_set_log_context = false; //定义一个全结局的标记,默认false
public  $log_context = []; //记录全局的日志内容,存储到数组中// 设置全局标记为true
public function setLogContext()
{$this->is_set_log_context = true;
}
//读取全局的日志数组内容,并将全局标记改为false
public function returnLogContext()
{$this->is_set_log_context = false;return $this->log_context;
}

然后修改上面的方法如下:

public function info($message, array $context = []): void
{if($this->is_set_log_context){ //如果设置了全局标记$set_context = $message;if(!empty($context)){$set_context.="context:".returnjson($context);}$this->log_context[] = $set_context; //则将本次的日志内容收集到全局的日志内容数组中}$this->log(__FUNCTION__, $message, $context);
}

效果如下:

image-20250522172340114

然后,在入口方法处调用一下:

public function step1($goods_id, $user_id)
{Log::setLogContext(); //设置全局标记入口$result = $this->step2($goods_id, $user_id, 100);$log_info_context = Log::returnLogContext(); //读取本次收集的日志数组内容,并将全局标记设为falseprint_r($log_info_context); //提取到所有的 Log::info(....) 中的内容,存储到数组中return $result;
}

这样一来,我在不改动calculateCookie()方法块的任何内容的情况下,把里面的Log::info(...) 的内容收集起来了。

这个思路,不仅限于PHP语言,其它的编程语言也类似,你可以自由发挥。

http://www.xdnf.cn/news/584965.html

相关文章:

  • 2025中青杯数学建模B题思路+模型+代码
  • 【TTS回顾】CosyVoice 深度解析:基于LLM的TTS模型
  • iOS 直播弹幕功能的实现
  • 前端三件套之html详解
  • DevOps体系之Jmeter
  • java面试每日一背 day2
  • MySQL错误1419(HY000)解决方案:SUPER权限缺失与二进制日志启用冲突的3种处理方式
  • 内存管理子系统学习记录
  • uniapp实现H5、APP、微信小程序播放.m3u8监控视频
  • AVL树的实现
  • 【线段树】P2846 [USACO08NOV] Light Switching G|LG4|普及+
  • 无人机集装箱箱号识别系统准确率如何?能达到多少?
  • 微服务架构中的 RabbitMQ:异步通信与服务解耦(一)
  • Linux探秘:驾驭开源,解锁高性能——基础指令(续集)
  • LeetCode 1340. 跳跃游戏 V(困难)
  • 【Harmony】【鸿蒙】List列表View如果刷新内部的自定义View
  • 力扣HOT100之二叉树: 236. 二叉树的最近公共祖先
  • vue3定于组件名字的几种方法
  • 杨校老师竞赛课之青科赛GOC5-6年级组模拟题
  • ISO 26262- 5 评估硬件度量值
  • 2025年中青杯赛题浅析-快速选题
  • 12kV 环保气体绝缘交流金属封闭开关设备现场交流耐压试验规范
  • Web前端开发(HTML、CSS快速入门)
  • 2024 年地理信息技术与应用技能大赛(选拔赛/初级)——实操试题
  • 部署Prometheus并通过Grafana展示界面
  • wx.getPrivacySetting接口needAuthorization一直返回false
  • vue element-plus 集成多语言
  • SQLynx:一款跨平台的企业级数据库管理工具
  • pdf图片导出(Visio和Origin)
  • 2025口语App实测Top5!练习口语app真实口碑