【问题标题】:Struct being populated with duplicate data over and over结构被一遍又一遍地填充重复数据
【发布时间】:2026-01-10 15:50:02
【问题描述】:

考虑以下代码:

<cfset result.enrollments = {} />
<cfset result.enrollments = getCorrectionList(SESSION.id,SESSION.term) />
<cfdump var="#result#" /><Cfabort/>


<cffunction name="getCorrectionList">
    <cfargument name="id" required="true" type="string" />
    <cfargument name="term" required="true" type="numeric" default="#getCurrentSemester().code#" />

        <cfset result = {} />
        <cfset result.status = 500 />
        <cfset result.message = 'Unknown Error' />

        <cfhttp url="THERE IS A REAL URL HERE" />
        <cfif cfhttp.statusCode EQ '200 OK'>
            <cfset courses = deserializeJson(cfhttp.fileContent,false) />

            <cfif courses.recordCount EQ 0>
                <cfset result.message = 'You are not currently enrolled in any courses for #ARGUMENTS.term#' />
                <cfdump var="#result#" />
                <cfreturn result />
            </cfif>
<!--- MORE STUFF --->

现在,当它运行时,我得到一个带有两个键 messagestatus 的结构输出。这是来自getCorrectionList 函数内部的转储。

然后我得到第二个结构输出,其中包含键 enrollmentsmessagestatus。在enrollments 键内是另一个结构体enrollmentsmessagestatus。在 enrollments 键内部是另一个具有相同键的结构,依此类推 50 次,最后一个结构为空。

似乎正在进行一些递归操作,但在哪里/如何?

我不知道发生了什么。正如您从我的代码中看到的那样,没有循环。我知道 URL 解析正确,它返回一个查询并有一个记录数。我可以在正确的位置看到数据转储。但是函数中的#result# 如何显示单个结构,而函数外部的#result# 显示重复自身的 50 深结构。这没有任何意义。

【问题讨论】:

  • (编辑)这是因为您在函数内部都使用了一个名为“result”的结构变量。由于函数内部的变量未本地化,因此您实际上是在捕获函数的结果 - 在其内部。从而创建一个循环引用。因此转储。解决方案是本地化函数局部变量。有趣的是,它只发生在 CF 中。我已经看到缺乏范围界定做了一些奇怪的事情,但这是一个新的;-)
  • 澄清一下,代码实际上并没有一遍又一遍地填充结构。看起来就是这样,因为 CFDump 在呈现值时无法解析循环引用。
  • 您需要 var 变量名为 result - 但我建议为它使用不同的名称..和 var 它。

标签: recursion coldfusion


【解决方案1】:

我不知道为什么 Leigh 和 Scott 实际上都没有给出他们的 cmets 答案,但他们都是对的。

您在函数外部引用了result

<cfset result.enrollments = getCorrectionList(SESSION.id,SESSION.term) />

在你的函数结束时你这样做:

<cfreturn result />

这实际上意味着您正在这样做:

<cfset result.enrollments = result />

意思是 result.enrollments 是对它自己的父 result 的引用。

&lt;cfdump&gt; 正在适当地显示循环引用。

正如他们所说,您需要在函数中本地化您的变量,或者通过varing 他们:

<cfset var result = {} />

或者明确地将它们放在local 范围内:

<cfset local.result = {} />

这将使函数的 result 成为离散变量,而不仅仅是对调用代码的另一个引用 result 变量。

你应该总是本地化你的函数变量,除非你特别想引用一个调用代码变量,在这种情况下,如果你明确地确定它的范围以使你的代码更清晰,它会让你的代码更清晰意思是,例如:

<cfset variables.result = {} />

但这不是你在这里的意思。本地化函数的变量。

【讨论】:

  • IMO,“好的答案”应该比我的 cmets 有更多的实质内容(最好是例子)。我决定休息一晚,但希望你能突然出现并在此期间发布一个更可靠的答案......你没有让你失望;-)
  • 嘿,很公平。我认为您的评论实际上已经足够彻底,但它让我写了更多,以便实际上在答案中做一个增值。
  • 我的印象是CF10函数内部默认本地化了变量,没有必要这样做。我猜是这样,但是因为我已经在函数之外有一个结果,它正在使用该引用而不是创建一个新的?
  • 其实,刚刚测试了我的理论,我错了。哇。这样做已经有一段时间了,我做了一个非常不正确的假设。无论哪种方式,奇怪的是我什至没有看到结果不是在本地设置的。谢谢。
  • @Leeish - 虽然变量绝对应该是 var/local 范围以避免这个问题,但有趣的是,这种行为只发生在 ACF 中。 Lucee 和 Railo 都返回一个只有两个键的结构:状态和消息。