组件上具有accessors = true的意外行为

时间:2015-02-25 23:36:20

标签: coldfusion cfml lucee

我正在尝试在Lucee上的组件上使用合成访问器(虽然这个问题在ColdFusion上也是如此)。

Repro代码:

// 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);

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

但是,当我运行此代码时,我看到了:

Dump output showing properties

注意如何填充属性。这没有问题,但我显然不明白accessors标志应该如何工作。我认为它只是为我合成一些存取方法(它有),但就是这样。

另请注意,如果我将CFC定义修改为而不是将访问者设置为true,那么转储显示为:

Dump with no properties

所以没有合成访问器(如预期的那样),但现在甚至没有显示属性(使用变量范围的值)。

我真的不明白“属性”和访问者设置的这种混淆吗?当然,访问者设置应该只影响是否创建了这些访问器方法?

如果我只是在其中一个平台上看到这个,我可能会把它归结为writeDump()如何解释属性定义的变幻莫测。但是ColdFusion 11上的行为是一样的,所以看起来我的行为似乎有些不同。

任何人都能解释一下吗?有没有解释它的文档?如果不是......嗯...为什么不呢?

我的基本担忧是,属性值没有“正确”存储,一旦我实现了更多的代码,可能会给我带来问题。

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

为了充分披露,这个问题是我在博客上提出的问题的摘要(“CFML: trying to understand accessors”)。复制是有意的,因为我的博客与本网站的受众不同。

2 个答案:

答案 0 :(得分:10)

如果没有accessors=true,则property声明只是元数据。

使用accessors=trueproperty声明会触发getter / setter的生成,因此propertyvariables范围项一对方法。

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

答案 1 :(得分:2)

这提出了ACF9。在此之前,属性文档中的定义是正确的:cfproperty声明是只是元数据。 (请参阅dump(getMetaData())。

在ACF9中,由于以下三个原因,这不完全正确:

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

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

  3. 属性属性控制ORM。

  4. 由于我了解了这些功能,因此我设计了所有(公共)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始终从转储中调用getter,而在Railo / Lucee中,将显示变量scope的值。因此,上述示例(getDebug()getName())不适用于Railo / Lucee。
    • 如果getter不公开或导致错误,则转储显示属性的空字符串(此处不确定,可能缺少属性)。
    • 忽略扩展CFC中的属性声明。这让我在使用继承的ORM实体中感到头痛,因为不允许两次声明属性。因此,您无法显示基本CFC中定义的属性。
    • Railo / Lucee似乎忽略了属性类型。所有访问器只接受并返回字符串(请参阅getMetaData())。
    • Minor:在激活访问者时在ACF中,但为属性取消激活getter和setter:property name="user" getter="false" setter="false";它仍然在转储中可见 - 它应该被隐藏。