组件上 accessors=true 的意外行为

Unexpected behaviour with accessors=true on a component

我正在尝试在 Lucee 上的组件上使用合成访问器(尽管这个问题在 ColdFusion 上似乎也一样)。

复制代码:

// Person.cfc
component accessors=true {

    property firstName;
    property lastName;

    function init(firstName, lastName){
        variables.firstName = arguments.firstName;
        variables.lastName = arguments.lastName;
    }

}

调用代码:

// person.cfm
person = new Person("Abigail", "Bowen");
writeDump(person);

注意我是如何在这里使用合成访问器的,我只是将参数值设置为同名变量范围的变量。

但是当我 运行 这段代码时,我看到了这个:

注意属性是如何填充的。这没有问题,但我显然不理解 accessors 标志应该如何工作。我以为它只是想为我合成一些访问器方法(它有),但仅此而已。

另请注意,如果我将 CFC 定义修改为 not set accessors to true,则转储显示如下:

所以没有合成访问器(正如预期的那样),而且现在甚至没有显示属性(无论是否具有变量范围的值)。

我真的不明白 "properties" 和访问器设置的这种混淆?当然访问器设置应该只影响那些访问器方法是否被创建?

如果我只在其中一个平台上看到这个,我可能会把它归结为 writeDump() 如何解释 属性 定义。但是 ColdFusion 11 上的行为是相同的,所以看起来确实存在一些我不太了解的行为差异。

谁能解释一下?有没有解释它的文档?如果不是...嗯...为什么不呢?

我的基本担心是 属性 值没有被存储 "properly",一旦我实现更多代码可能会给我带来问题。

更新: 至少在 ColdFusion 上,这似乎只是 writeDump() 行为的一个变化,因为如果属性有吸气剂(无论是否设置了 accessors 标志),那么 属性 值开始出现在转储中。不过 Lucee 的情况并非如此,所以这里仍然有一个问号。

为了全面披露,这个问题是我在我的博客 ("CFML: trying to understand accessors") 上也提出的一个问题的摘要。重复是故意的,因为我的博客与本网站的受众不同。

没有 accessors=trueproperty 声明只是元数据。

对于 accessors=trueproperty 声明会触发 getter/setter 的生成,因此 property 既是 variables 范围项 一对方法。

在您的构造函数中,您分配给 variables 范围项——这与使用生成的 setter 相同——当 CFML 转储组件时,它会看到 property 元数据和生成的 getter,因此它显示这些属性具有的值(因为它可以轻松安全地调用生成的 getter)。

ACF9 就这样诞生了。在那之前,属性 文档中的定义是正确的:cf属性 声明 只是元数据 。 (参见转储(getMetaData())。

在 ACF9 中,这不再完全正确,原因有 3 个:

  1. 使用 accessors=true 为每个 属性 生成一个 getter 和 setter 并且这些访问器读取和写入 变量范围。 Cf属性 不再只是元数据,而是对实例的行为有直接影响。我喜欢将其视为真正的 OO 属性(偶然引入)的 CF 版本。

  2. cfdump 实现根据 属性 声明更改其行为。如果定义了 property name; 并且方法 getName() 存在(生成或实现)它被添加到转储的 属性 部分。

  3. 属性 属性控制 ORM。

自从我了解了这些功能后,我将所有 (public) CFC 设计为在丢弃时看起来正确,例如。当我想让它可见时,我只使用 属性 声明 (+ getters)。此外,您可以实现仅由转储调用且在实例化时不产生任何成本的方法:

struct function getDebug(){
    var x = doSomethingExpensive();
    return { "Foo":f, "Bar":b, "Baz":x };
}

//or for a user iterator
string function getName(){
    return qUsers.name[index];
}

我知道的一些注意事项:

  • ACF 总是从转储中调用 getters,而在 Railo/Lucee 中显示变量范围的值。因此,上述示例(getDebug()getName())不适用于 Railo/Lucee。
  • 如果 getter 不是 public 或导致错误,转储显示 属性 的空字符串(此处不确定,可能是 属性相反)。
  • 属性 扩展 CFC 中的声明将被忽略。这让我在使用继承的 ORM 实体中有些头疼,因为你不允许声明一个 属性 两次。因此,您无法显示在基本 CFC 中定义的 属性。
  • Railo/Lucee 似乎忽略了 属性 类型。所有访问器只接受 return 字符串(请参阅 getMetaData())。
  • 轻微:在 ACF 中,当您激活访问器时,但为 属性 停用 getter 和 setter:property name="user" getter="false" setter="false"; 它在转储中仍然可见 - 它应该隐藏起来。