2011-08-26 128 views
5

我正在寫一個函數,循環註冊頁面上的一些信息。在循環內,我試圖調用基於數組的函數。我遇到的問題實際上是正確調用函數,因爲我試圖將變量作爲函數名稱的一部分。如何在ColdFusion中將變量名稱作爲函數名稱的一部分?

這裏是我的代碼:

<cfscript> 
fields = arraynew(1); 
fields[1] = 'r_email'; 
fields[2] = 'r_uname'; 
fields[3] = 'r_pass'; 

for(i = 1; i lte arraylen(fields); i = i + 1) 
{ 
    func = fields[i].split('r_'); 
    func = 'validate_#func[2]#(#fields[i]#)'; 
} 
</cfscript> 

所以,我有三個功能:validate_email,validate_uname,validate_pass。如果我拋出一個writeoutput(),並嘗試輸出函數的結果,它們不起作用。

下面是代碼:

<cfscript> 
fields = arraynew(1); 
fields[1] = 'r_email'; 
fields[2] = 'r_uname'; 
fields[3] = 'r_pass'; 

for(i = 1; i lte arraylen(fields); i = i + 1) 
{ 
    func = fields[i].split('r_'); 
    func = 'validate_#func[2]#(#fields[i]#)'; 
    writeoutput('#func#'); 
} 
</cfscript> 

現在,我明白,當你使用writeoutput(),和你調用一個函數,你需要在兩端的哈希符號。所以,假設我這樣寫:

writeoutput('#validate_#func[2]#(#fields[i]#)#'); 

它不起作用,因爲第二個散列符號會取消函數調用。這是怎樣的功能最終應該看(例如電子郵件):

writeoutput('#validate_email('[email protected]')#'); 

我怎樣才能用正確的變量名稱替換「電子郵件」(#validate_email ......),而且還有功能的工作?我希望我能夠理解這一點!

回答

10

函數是變量太多,所以以相同的方式可用於數組,結構和範圍括號表示法,可以使用它來訪問動態變量名稱(因此動態函數名)

例如:

<cfloop index="Field" list="email,uname,pass"> 
    <cfset Result = Variables['validate_'&Field](Variables['r_'&Field]) /> 
    ... 
</cfloop> 

那麼......不完全。由於Adobe ColdFusion,請一個bug,不喜歡的工作(儘管它在其他CFML引擎,如Railo),你必須把它分成兩行,像這樣:

<cfloop index="Field" list="email,uname,pass"> 
    <cfset TmpFunc = Variables['validate_'&Field] /> 
    <cfset Result = TmpFunc(Variables['r_'&Field]) /> 
    ... 
</cfloop> 

(這假設兩個函數和字段都在variables範圍內,如果他們不需要參考他們所在的範圍)。

如果函數處於狀態爲object的對象中,則此方法存在問題失去對這些變量的引用。

在CF10上,有invoke函數。較早版本的CF需要使用cfinvoke標籤。


(作爲一個方面說明,CF10確實添加了參考作用的結果與括號標記的反能力,即doSomething()[key]這有時進來有用。)

+0

這不是CF中的錯誤,Peter:它從來沒有實現過。你可能想修改你的評論來達到這個效果。否則就地答覆。 –

+3

'Variables.Bob()'和'Variables ['Bob']()'應該沒有區別,但是第二個拋出錯誤。我稱這是一個括號表示中的錯誤,而不是一個未實現的功能。 –

+0

謝謝你。我收到的兩個建議都很好。我是CF的新手,所以我會和人羣一起使用,而不是使用其他人。另一個更容易一點,但如果有問題,我不想進入!再次感謝! –

1

彼得的回答是現貨(除我評論過的「bug」引用)。如果不在CFScript塊的中間,另一個選項是<cfinvoke>將一個字符串作爲其METHOD屬性值,並且顯然可以採用任何喜歡的動態值。

對於您的具體情況,這不是那麼有幫助,但記住它很方便。

我不會使用evaluate()方法。

0

我會補充說,在ColdFusion 6.1和遷移到Java之前,evaluate()總是被認爲是對性能的詛咒,但從6.1開始,它只是評估表達式,然後創建一個帶有包含字符串的內聯PageContext作爲其代碼。

非常光滑,非常高效。

那麼,要實現你的目標的最簡單,最直接的方法是:

<cfset result = evaluate("validate_#Field#(variables.r_#Field#)") /> 

所以假設你有一個名爲「用戶名」欄,這將是下面的方法調用相當於:

<cfset result = validate_username(variables.r_username) /> 

以及它返回的任何內容將被分配給variables.result。

在測試中,它實際上超過了將方法重新分配給新名稱的方括號表示法。目前我沒有統計數據,但速度更快,因爲包含速度更快(並且發生在不同的分析/編譯階段),而不是變量賦值。

+0

至於Adam對evaluate()的警告,除了愚蠢並使用它來評估用戶提供的值(如允許用戶實質上輸入代碼 - 是的,它已完成),沒有理由避免使用此方法。 沒有揮之不去的性能或安全問題。 – jrypkahauer

0

另外一個辦法處理這一問題是使用UDF如下列:

<cffunction name="callMethod"> 
     <cfargument name="methodName" type="string" required="true" /> 
     <cfargument name="methodArgs" type="struct" default="#{}#" /> 
     <cfset var rslt = 0 /> 
     <cfinvoke method="#arguments.methodName#" argumentcollection="#arguments.methodArgs#" returnvariable="rslt" /> 
     <!--- account for the possibility that the method call wiped out the rslt variable ---> 
     <cfif structKeyExists(local,'rslt')> 
      <cfreturn rslt /> 
     </cfif> 
    </cffunction> 

如果需要你可以這樣:

<cfinclude template="invokerudf.cfm" /> 
    <cfscript>...</cfscript> 

或標籤包起來折騰它變成了一個CFC:

<cfset retval = createObject("methodinvoker").callMethod(methodName,methodArgs) /> 

有很多很多方法可以實現這一點......現在就把各種想法扔出去。

相關問題