变量转储显示数据但 returns 未定义

Variable dump shows data but returns as undefined

希望这是一个 "DOH" 时刻,但我不明白为什么会这样。我正在使用服务对象获取 Google 的目录 API 中的组成员。创建服务对象后,我使用以下几行来测试

<cfset themembers = groupservice.members().list("[My Group Key]").execute()>
<cfdump var="#themembers#">
<cfoutput>
   Isnull? #isNull(themembers.etag)#<br />
   SKExists? #structKeyExists(themembers,"etag")#<br />
   Is Defined? #isDefined("themembers.etag")#
</cfoutput>

代码的结果输出如下所示

查看转储,我可以看到 etag 字段中有数据以及一组成员。但是,当我尝试输出键值时,出现了未定义的错误。我写了一个测试输出行,它显示为 NULL,并且在密钥确实存在时未定义。

当变量的转储清楚地显示数据时,这怎么可能?我在这里错过了什么?

@Leigh

<cfdump var="#groupservice.members()#">
<cfdump var="#groupservice.members().list('[groupkey]')#">

这是上面两行的转储。列表方法只是 returns 我传入的组密钥名称 - 只有在我 运行 执行方法之后我才真正获得成员列表(第一张图片中的输出)但就像etag - 它告诉我成员未定义。

简答:

显然这属于 "Never trust CFDump. Sometimes it lies." 的一般规则,例如,变量 themembers 并不是真正的结构。它是 Members class 的实例。不要使用点符号,而是尝试调用 class:

的相关方法
<cfset eTag = themembers.getETag()>
<cfset membersArray = themembers.getMembers()>
..

更长的答案:

虽然 CFDump 是一个很好的调试工具,但它倾向于 "pretty presentation" 而不是准确性,因此您不能总是相信您所看到的。将 themembers 显示为 "struct" 的原因是因为 ColdFusion 自动将 Java 类型与 ColdFusion 类型 匹配。如果你看一下 Members 的 class 层次结构,你可以看到它实现了 java.util.Map(通过 AbstractMap),它自动匹配到一个CF结构。因此,为什么 CFDump(误导性地)将其显示为一个。

- com.google.api.services.admin.directory.model.Members
- com.google.api.client.json.GenericJson
- com.google.api.client.util.GenericData
- java.util.AbstractMap   
- java.lang.Object

虽然java对象类似于结构,但在某些方面,它们并不是一回事。因此,某些函数的结果可能与您通常对结构的预期不同,这就是这里发生的情况。即您可以查看一些 属性 名称,就像您可以使用结构键一样,但您不能直接访问 key/property 值。

也就是说,从技术上讲,您 应该 已经能够使用点表示法访问 "eTag" 和 "members" 属性。原因是 CF 对某些 java 对象应用了一些语法糖,以允许使用点表示法直接访问属性。就像它们是常规结构键一样。

ColdFusion can automatically invoke get_PropertyName_() and set_PropertyName_(value) methods if a Java class conforms to the JavaBeans pattern. As a result, you can set or get the property by referencing it directly, without having to explicitly invoke a method.

但是,正如文档稍后指出的那样,存在一些例外情况。这个 class 似乎是其中之一。因此,您需要显式调用适当的 getPropertyName() 方法。归根结底,这可能是最好的做法,因为直接访问并不总是有效。

示例:

// Simulate Members object 
obj = createObject("java", "com.google.api.services.admin.directory.model.Members").init();
// Initialize property values
obj.setEtag("If you are seeing this text, it worked.");
obj.setMembers( [] );

writeOutput("<br>IsNull? "& isNull(obj.etag));
writeOutput("<br>Key List: "& structKeyList(obj));
writeOutput("<br>Exists? "& structKeyExists(obj, "etag"));
writeOutput("<br>IsDefined? "& IsDefined("obj.etag"));
writeOutput("<br>getETag(): "& obj.getETag());
writeDump(var=obj.getMembers(), label="getMembers()");

结果:

IsNull? YES
Key List: etag,members
Exists? YES
IsDefined? NO
getETag(): If you are seeing this text, it worked.
getMembers(): (empty array)

我解决未定义结构值的方法是使用 structKeyArray 来创建结构中键的数组。然后,遍历数组以检查结构键是否存在。示例:

 //result is a structure which can have undefined values
  myAry = structKeyArray(result);
    myLen = arrayLen(myAry);
    for (i=1; i <= myLen;i=i+1){
     if(!structKeyExists(result, "#myAry[i]#")){
      result[myAry[i]] = "";
     }
    }

当然,您可能不想要空白字符串,但在我的情况下,如果它不存在,这就是我要找的。