我正在使用 ColdFusion 9。
我包含一个 UDF 库 (UDF_Library.cfm),其中只有几个函数。当我尝试访问这些函数时,收到一条错误消息,提示“变量 POPUP 未定义”。该库作为 onRequestStart 方法的第一部分包含在 Application.cfc 中。
这是我如何包含该库:
<cfscript>
// INCLUDE UDF_LIBRARY
include "/UDF/UDF_Library.cfm";
</cfscript>
以下是图书馆的内容:
<cfscript>
function popUp() {
return "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
}
</cfscript>
我知道该功能有效。当我直接将函数写到文件中并调用该函数时,它工作得很好。
<cfscript>
writeOutput(popUp());
function popUp() {
return "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
}
</cfscript>
为什么在加载页面的任何部分之前,在 application.cfc 文件的 UDF 中包含该函数时看不到该函数?
我认为这里所有指南中缺少的信息是理解变量作用域如何工作的建议,这与 Application.cfc 事件处理程序可能声明一个函数无关。
Application.cfc 事件处理程序不会对最初在其中声明的事物赋予任何神奇的持久性:仍然需要将任何声明的变量或函数放入适合其访问方式的范围中。在 onRequestStart (或 onRequest)中声明变量并不会神奇地使该变量可用于请求中的所有内容。函数只是一个变量。
当一个人包含一个文件时 - 就像你正在做的那样 - 任何变量声明(以及相应的函数声明)都驻留在将它们放入的任何范围内。如果一个人声明了一个函数,并且不对其进行任何操作,那么该函数仅存在于变量范围。
如果在 onRequestStart() 中声明一个函数,该函数只是在每个请求开始时创建的 Application.cfc 实例中的一个方法,那么该函数将被放入该 CFC 实例的变量范围中。并且将持续与该 CFC 实例的生命周期一样长。就 onRequestStart() 的执行而言,CFC 实例的持续时间与运行 onRequestStart() 所需的时间一样长。所以时间不长。
另一方面,onRequest() 不是一个事件处理程序(像 onRequestStart() 一样),它是一个事件拦截器:它发生而不是它拦截的事件。一般来说,onRequest() 从字面上包括所请求的模板。因此,所请求的模板与包含它的 CFC 实例(通过 onRequest())在同一内存空间中运行,因此包含的模板共享 CFC 实例的变量范围,因此变量范围可用于 onRequest()。因此,如果 onRequest() 包含一个 UDF 库,该库在变量作用域中声明了一堆函数...这与 onRequest() 拦截器中包含的主请求文件的变量作用域相同。与任何其他 CFC 实例方法(包括文件)相同。
所以......这样做的结果是,简单地在 onRequestStart() 中包含一个充满函数的文件并不能达到你想要的效果,因为 - 希望现在 - 显而易见的原因。同样,在 onRequest() 中包含一个充满函数的文件并不会赋予它们神奇的持久性:它们只是被放入变量范围中。这意味着它们将可以访问所请求的模板及其包含的任何模板。它们将不可用于任何自定义标记,也不可用于该请求中使用的任何 CFC 实例。
如果希望某个函数(或“某些函数”)可供请求中的任何代码使用,则需要将这些函数放入
request
范围(或另一个共享范围)。执行此操作的方法与任何变量相同:
request.something = somethingElse;
就是这样。这是唯一的方法。无论您如何包含它,包含一个充满功能的文件都不会是您想要做的事情的完整解决方案。
我相信要使这些功能普遍可用,它们必须包含在 onRequest() 中,而不是 onRequestStart() 中。
我认为最好将 UDF 库存储在应用程序或会话等持久范围中。就我个人而言,我会遵循 Ben Nadel 在这里讨论的模式:http://www.bennadel.com/blog/257-My-ColdFusion-User-Defined-Function-Library-Structure.htm。