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

最近接手了一个公司的老系统的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.pswp.cn/pingmian/82225.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

V9数据库替换授权

文章目录 环境文档用途详细信息 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;9.0 文档用途 1、本文档用于指导V9数据库替换授权。 2、V9数据库授权文件为license.dat。 详细信息 1、上传新的授权文件到服务器并修改授权文件属主为…

初识 Flask 框架

目录 1. Flask 框架概述 1.1 安装 Flask 1.2 创建你的第一个 Flask 应用 1.3 运行 Flask 应用 2. Flask 路由与视图函数 2.1 动态路由 2.2 支持多种 HTTP 请求方法 2.3 使用 Jinja2 模版渲染 HTML 2.5 模版继承与块 3. Flask 表单处理与用户输入 3.1 安装 Flask-WTF …

《深入剖析:Python自动化测试框架之unittest与pytest》

unittest作为Python标准库的一部分&#xff0c;犹如一位沉稳可靠的“老工匠”&#xff0c;默默为无数项目提供着坚实的测试基础。它诞生于Python社区长期的实践沉淀&#xff0c;拥有一套标准化的测试体系&#xff0c;就像一套精密的仪器&#xff0c;各个部件各司其职。 unitte…

【Python 命名元祖】collections.namedtuple 学习指南

&#x1f4da; collections.namedtuple 学习指南 命名元组&#xff08;namedtuple&#xff09;是 Python collections 模块中一种增强型元组&#xff0c;支持通过字段名访问元素&#xff0c;同时保持元组的内存效率和不可变性。 一、基础用法 1. 定义命名元组 from collectio…

iOS知识复习

block原理 OC block 是个结构体&#xff0c;内部有个一个结构体成员 专门保存 捕捉对象 Swift闭包 是个函数&#xff0c;捕获了全局上下文的常量或者变量 修改数组存储的内容&#xff0c;不需要加_block,修改数组对象本身时需要 weak原理 Weak 哈希表 &#xff08;散列表&a…

手眼标定:九点标定、十二点标定、OpenCV 手眼标定

因为一直使用6轴协作机器人&#xff0c;且主要应用是三维视觉&#xff0c;平常的手眼标定基本都是基于OpenCV来计算的&#xff0c;听说有九点标定和十二点标定&#xff0c;顺便了解下。 目录 1.九点标定1.1 基本原理1.2 关于最小二乘法1.3 具体示例 2.十二点标定3.OpenCV 手眼标…

CSS之元素定位

元素定位 一、什么是元素定位 元素定位&#xff08;CSS Positioning&#xff09; 是指通过CSS的 position 属性控制HTML元素在页面中的布局方式。它决定了元素如何相对于其父元素、视口或其他元素进行位置调整。 CSS的 position 属性用于控制元素在页面上的定位方式&#xff…

测试工程师如何通俗理解和入门RAG:从“查资料”到“写答案”的智能升级

1. 为什么要学习RAG?——从“查资料”到“写答案”的飞跃 背景:你已经掌握了Embedding技术,能将文档、代码、测试用例等离散信息转化为向量,用于相似度匹配。 痛点:但仅靠向量匹配找到相关文档后,如何快速生成答案?如何避免“找到文档却不会总结”的尴尬? RAG的价值:…

数量优势:使用Bagging和Boosting的集成模型

文章目录 装袋法&#xff08;Bagging&#xff09;和提升法&#xff08;Boosting&#xff09;利用集成学习创建强大的模型装袋法&#xff08;Bagging&#xff09;&#xff1a;为机器学习模型增加稳定性装袋法示例 提升法&#xff08;Boosting&#xff09;&#xff1a;减少弱学习…

5G基站选择±10ppm晶振及低相噪技术解析

在5G通信技术飞速发展的时代&#xff0c;5G基站作为核心基础设施&#xff0c;其性能的优劣直接影响着整个通信网络的质量。晶振作为5G基站中的关键器件&#xff0c;对基站的频率稳定性、信号传输质量等起着至关重要的作用。 5G基站对晶振的要求 &#xff08;一&#xff09;高…

嵌入式<style>设计模式

每天分享一个web前端开发技巧。 今天分享的主题是&#xff0c;如何提升前端代码的内聚性。我们在写<style></style>的时候&#xff0c;往往把大量无关联的样式写在同一个<style>下&#xff0c;而且离相关的html元素很远&#xff0c;这样导致每次想修改某个元…

简单数学板子和例题

线性丢番图方程 axbyc dgcd(a,b)&#xff0c;若c|d&#xff0c;有无穷整数解 x x 0 b d n , y y 0 − a d n xx_0{b\over d}n,yy_0-{a\over d}n xx0​db​n,yy0​−da​n POJ 1265 poj真难用&#xff0c;abs一直报错&#xff0c;万能头也不能用&#xff0c;给我调红温了 …

深度解析视频剪辑SDK开发:从AI字幕提取到多端原生插件集成-优雅草卓伊凡

深度解析视频剪辑SDK开发&#xff1a;从AI字幕提取到多端原生插件集成-优雅草卓伊凡 引言&#xff1a;视频剪辑技术的演进与市场需求 近年来&#xff0c;短视频和社交媒体的爆发式增长推动了视频剪辑技术的快速发展。优雅草卓伊凡及其团队近期接到一个客户需求&#xff1a;开…

对WireShark 中的EtherCAT抓包数据进行解析

对WireShark 中的EtherCAT抓包数据进行解析 EtherCAT数据包结构 EtherCAT数据帧结构如下&#xff1a; 采用 Python 实现对 EtherCAT 数据包进行解析 import numpy as np import matplotlib.pyplot as plt from IPython import embed from collections import Counter import …

基于SpringBoot的校园电竞赛事系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

数据湖和数据仓库的区别

在当今数据驱动的时代&#xff0c;企业需要处理和存储海量数据。数据湖与数据仓库作为两种主要的数据存储解决方案&#xff0c;各自有其独特的优势与适用场景。本文将客观详细地介绍数据湖与数据仓库的基本概念、核心区别、应用场景以及未来发展趋势&#xff0c;帮助读者更好地…

Mysql 刷题Day09

LC 585 2016年的投资 思路&#xff1a; 本题思路好想 &#xff0c; 就是把2015年投资相同的找出来 &#xff0c;再找出这其中经纬度不同的id对应的2016年的保险。 实际操作中&#xff0c; 发现用group by很麻烦&#xff0c; 那么想到窗口函数也能 分组进行统计 利用 count(…

Lambda表达式的方法引用详解

Lambda表达式的方法引用详解 1. 方法引用的概念与作用 定义:方法引用(Method Reference)是Lambda表达式的一种简化写法,允许直接通过方法名引用已有的方法。核心目的:减少冗余代码,提升可读性,尤其在Lambda仅调用一个现有方法时。语法符号:双冒号 ::。2. 方法引用的四种…

记录python在excel中添加一列新的列

思路是&#xff0c;先将需要添加为新的列存储到一个暂时的列表中&#xff0c;然后用到以下函数来存储 data_.loc[:, "新列的名字"] save_list_ 上面的save_list_就是暂时存储了信息的列表了。 以下是我的代码&#xff0c;供以后快速回忆。 schools_data {"98…

关于flutter中Scaffold.of(context).openEndDrawer();不生效问题

原因&#xff1a; 在 Flutter 中&#xff0c;Scaffold.of(context) 会沿着当前的 context 向上查找最近的 Scaffold。如果当前的 widget 树层级中没有合适的 Scaffold&#xff08;比如按钮所在的 context 是在某个子 widget 中&#xff09;&#xff0c;就找不到它。 解决办法…