当前位置: 首页 > 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语言,其它的编程语言也类似,你可以自由发挥。

相关文章:

  • 网工每日一练
  • WebRTC:实时通信的未来之路
  • OceanBase数据库全面指南(数据操作篇DML)
  • SpringBoot 2.X 版本整合 Swagger + Knife4j 接口文档
  • PyQt学习系列03-动画与过渡效果
  • 04-Web后端基础(基础知识)
  • 网络编程中的 Protobuf 和 JsonCpp 全面解析
  • [Vue]路径跳转和路由高级设置
  • Kubernetes上的爬虫排队术——任务调度与弹性扩缩容实战
  • Qt控件:显示控件
  • Python 实现Web 请求与响应
  • SpringBoot开发——Spring Boot异常处理全攻略:五大方案实战对比
  • Redis 5.0.10 集群部署实战(3 主 3 从,三台服务器)
  • 2025年系统架构师---综合知识卷
  • webpack构建速度和打包体积优化方案
  • Qt无边框界面添加鼠标事件
  • 【推理加速】TensorRT C++ 部署YOLO11全系模型
  • 车载网关设计原则 ---- 透明性与诊断可追溯性
  • 分贝计如何帮助改善睡眠环境
  • 常见排序算法详解及其复杂度分析
  • 合肥网站制作哪家强/网络推广员上班靠谱吗
  • 手机浏览器下载app/个人如何做seo推广
  • 在线代理网页免费/怎么进行seo
  • 网站系统管理计划/广州网络运营课程培训班
  • 建设部网站业绩补录/优化分析
  • 提供信息门户网站建设/sem外包