【问题标题】:Any way to enforce a property's type in a CFC?有什么方法可以在 CFC 中强制执行属性类型?
【发布时间】:2015-04-20 11:05:06
【问题描述】:

我在这里遇到了一些奇怪的类型转换问题,并非特定于 Lucee(也在 Railo 中)。可能是我只是在这里错过了一些关键点......

我有一个组件:

<cfcomponent output="false">
    <cfproperty name="thisId" type="String" default="-1" />
    <cfproperty name="thatId" type="String" default="-1" />
</cfcomponent>

这两个属性都明确地输入为字符串。我希望当我尝试将对象或数字设置为其中之一时,代码将返回错误。 但是,由于我现在已经习惯了 cfml 为我进行类型转换,所以我从来没有考虑过在这里设置一个数字根本没有问题的事实。事实上,我假设我在这里尝试设置的所有数字都会为我转换为字符串。

但似乎情况并非如此。 在以序列化结构的形式实现了一些包含这些组件的派生类的 REST 调用之后,我注意到有些作为整数包含,有些作为字符串包含。当我注意到这一点时,我转储了组件本身,并注意到在预期字符串作为属性的地方设置了一个数字,输入已被覆盖为数字。

Railo / Lucee 仍然验证的事实在我看来毫无用处。验证严格类型并抛出错误/传入正确类型的变量,或者验证松散类型并在可能的情况下转换为 CFC 期望的类型。 Railo / lucee 在这里实现了松散的类型验证,但仍然决定以原始类型传递变量,而不是 cfc 期望的每个 sé。

鉴于我现在不想将每个数字都转换为字符串,这里是否有一个简单的疏忽可以挽救我的打字?

(我已经在 Lucee 邮件列表中发布了这个,但没有任何结果,只是人们确认了我已经说过的话/忽略了这不是预期行为的可能性。)


更新(亚当要求): 我看到的是以下内容(在我上面描述的 cfc 组件中):

<!--- setting a string returns a string afterwards, as expected since the property is a type string initialy --->
<cfset componentName.setThisId('1') />
<cfset local.thisIsStillAString = componentName.getThisId() />

<!--- setting a number returns a number, which means we can no longer assume the property is a string, as it was initially set up --->
<cfset componentName.setThatId(12345) />
<cfset local.thisIsNoLongerAString = componentName.getThatId() />

在这两种情况下,我都希望: - 输入变量将被严格评估为字符串,这意味着第二个示例会引发错误,因为它实际上是一个数字 - 输入变量将被松散地评估为字符串,但在通过评估时将被强制转换为字符串,这意味着第二个示例将通过但最终将返回一个字符串,而不是数字。

在任何情况下,我都希望保留属性的原始类型,而是将其更改为您尝试设置的任何类型,只要它通过当前的松散评估即可。

【问题讨论】:

  • 因为“-1”是一个字符串,所以它会通过字符串验证。我不怀疑您正在感知一些问题,并且我认为您在以“似乎并非如此”开头的段落中对此进行了描述。然而,当你描述某种问题时,你是一个很大的模糊。您能否真正向我们展示您认为不正确的行为,而不是简单地告诉我们。
  • @AdamCameron:添加了我在说什么的简短解释。希望这有助于解决问题。
  • 干杯。 CFML 中的类型检查正是:类型检查。不要输入“设置”。因此它会检查某个值是否可以用作给定类型。然而,它根本不会改变它的类型。它是一种动态类型的语言,因此它仅在类型必须为[某些给定功能]更改时才更改值的类型。例如,如果您有a = "1"; b = a + a;,则在内部它将“1”转换为1。但它不会将a 更改为包含数字而不是原始字符串。它的反向工作方式相同(数字到字符串)。这正是 CFML 的工作方式。

标签: coldfusion casting railo cfc lucee


【解决方案1】:

据我了解,内置的访问器设置器会自动进行类型验证,但只会在必要的情况下进行转换

数字/字符串/日期/布尔值都被认为是“简单的”,这就是数字数据通过“字符串”类型验证的原因。因此,因为它通过了验证,所以跳过了强制转换。就个人而言,我希望它进行更严格的验证,但这是 bugtracker 的问题。

现在,如果您必须确保只有实际的字符串数据可以进入这些属性,您可以覆盖为属性生成的设置器以进行更严格的类型转换和/或验证(我只在 Lucee 上测试过):

/** Example.cfc */
component accessors=true {
    property type="string" name="thisId";
    property type="string" name="thatId";

    public function setThisId(required string newId) {
        // convert numeric value to string value
        if (isNumeric(newId)) {
            newId = toString(newId);

        // throw an exception for non-string/numeric values
        // !isSimpleValue() is a catch-all btw, structs and arrays will
        // be prevented by the "newId" argument's type hint
        } else if (isBoolean(newId) || isDate(newId) || !isSimpleValue(newId)) {
            throw(message="Invalid value specified for thisId");
        }

        variables.thisId = newId;
        return this;
    }
}

var example = new Example();

example.setThisId(54321);
example.setThatId(54321);
writeoutput(serializeJson(example)); //{"thisId":"54321","thatId":54321}

// throws exceptions:
example.setThisId(true);
example.setThisId({});

最后,回到“必要时可能的投射”部分。对于给定的示例,如果您尝试将组件实例传递给 setThisId() 方法,则类型验证步骤将失败,这意味着类型转换对于操作成功是必要的。然后检查该值是否存在类型转换的可能性。如果组件(并且这只适用于 Railo/Lucee)定义了 _toString()“魔法方法”,那么类型转换是可能的。由于这是可能的,然后将组件转换为字符串,然后将结果传递给setThisId()。如果组件上没有定义该魔术方法,则无法进行类型转换,并引发异常。类似地,对于结构/数组,类型转换是必要的,但不是可能的,因为没有为这些类型定义自动序列化,从而导致抛出异常。

TL;DR

您可以覆盖 setter 访问器以执行更严格的类型验证/类型转换。

【讨论】:

    【解决方案2】:

    要将它们强制为字符串(不是数组或结构),请将accessor=true 与您的&lt;cfproperty&gt; 一起使用并使用setter。

    但是,如果您在谈论 SerializeJSON() 将数字字符串视为整数,则 type="string" 无法强制执行。它与SerializeJSON() 函数的行为有关。如果您真的想将它们作为字符串强制执行,请尝试https://github.com/bennadel/JsonSerializer.cfc

    【讨论】:

    • 我已经按照你的建议做,但我不是在谈论在字符串属性中设置结构。我说的是可以根据 Railo 转换为字符串的变量类型,例如来自数据库查询对象的数字类型。在我的 CFC 的字符串属性中设置此变量时,Railo 将该数字验证为可能的字符串,但仍将原始变量设置为我的 CFC 中的所有数字荣耀,不管它是字符串属性,而不是数字属性。我不是在谈论 serializeJSON()。
    • @dreagan 除了查询、数组或结构/对象之外的任何东西实际上都作为字符串在 CFML 中存储和操作。因此,数字也是字符串。
    • 我可以同意,但这并不意味着数字数据类型实际上是字符串数据类型,那么为什么缺少转换/正确验证呢?如果它存储为字符串,为什么不将数字转换为实际的字符串数据类型?我完全赞成松散的打字,但我所说的仍然存在,如果您不强制执行数据类型,那么对数据类型执行验证绝对没有意义。
    猜你喜欢
    • 2019-09-02
    • 2021-05-22
    • 2010-09-19
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 2015-01-28
    • 2017-06-15
    • 2012-02-11
    相关资源
    最近更新 更多