復雜項目中通過使用全局變量解決問題的思維方式

最近接手了一個公司的老系統的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
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/82225.shtml
英文地址,請注明出處:http://en.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;就找不到它。 解決辦法…