2011-08-26 17 views
5

Estoy escribiendo una función que recorre un poco de información en una página de registro. Dentro del ciclo estoy tratando de llamar funciones basadas en una matriz. Lo que estoy teniendo problemas con esto es llamar a las funciones correctamente, porque estoy tratando de incorporar una variable como parte del nombre de la función.¿Cómo puedo llamar un nombre de variable como parte de un nombre de función en ColdFusion?

Aquí está mi código:

<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> 

Por lo tanto, tienen tres funciones: validate_email, validate_uname, validate_pass. Si lanzo un writeoutput(), e intento dar salida a los resultados de la función, no funcionan.

Así es que el código:

<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> 

Ahora, entiendo que cuando se está utilizando writeoutput(), y que está llamando a una función, es necesario el símbolo de hash en cada extremo. Por lo tanto, digamos que lo escribo así:

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

No va a funcionar, porque el símbolo de hash segundo anula la llamada de función. Esta es la forma en la función última instancia, debe buscar (ejemplo de correo electrónico):

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

¿Cómo puedo reemplazar a 'e-mail' (#validate_email ...) con el nombre de la variable adecuada, y todavía tienen la función de trabajo? ¡Espero haber hecho esto comprensible!

Respuesta

10

funciones son variables también, así que de la misma manera se puede utilizar la notación de soporte para las matrices, estructuras, y alcances, se puede usar esto para acceder a los nombres dinámicos variables (y los nombres de las funciones de este modo dinámico)

Por ejemplo:

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

Bueno ... no del todo. Debido a un fallo en Adobe ColdFusion, eso no funciona así (aunque lo hace en otros motores de CFML, como Railo), y hay que dividirlo en dos líneas, así:

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

(Este asume que la función y los campos están en el alcance variables; si no es así, debe consultar el alcance en el que se encuentran)

Este método tiene un problema si la función estaba en un objeto con estado. pierde referencia a esas variables.

En CF10, existe la función invoke. Las versiones anteriores de CF necesitan utilizar la etiqueta cfinvoke.


(Como nota al margen, CF10 añadía la capacidad inversa en incluir resultados de la función con la notación de corchetes, es decir doSomething()[key] que viene en útil a veces.)

+0

No es un error en CF, Peter: simplemente nunca se ha implementado. Es posible que desee revisar su comentario a tal efecto. De lo contrario, una respuesta puntual. –

+3

No debería haber diferencia entre 'Variables.Bob()' y 'Variables ['Bob']()'; sin embargo, el segundo arroja un error. Llamo a eso un error en la notación de corchetes, no una característica no implementada. –

+0

Gracias por esto. Ambas sugerencias que recibí funcionan de maravilla. Soy nuevo en CF, así que voy con la multitud y uso esto en lugar de otro. El otro es un poco más fácil, pero si hay un problema, ¡no quiero entrar en eso! ¡Gracias de nuevo! –

1

respuesta de Pedro es impecable (excepto el "error" de referencia que comenté). Otra opción si uno no está en el medio de un bloque CFScript es que <cfinvoke> toma una cadena como su valor de atributo METHOD, y eso puede, obviamente, tomar cualquier valor dinámico que le guste.

Esto no es tan útil para su situación específica, pero es útil tenerlo en cuenta.

NO utilizaría el enfoque de evaluación().

0

Añadiré que antes de ColdFusion 6.1 y el cambio a Java, evaluar() siempre se consideró anatema para el rendimiento, pero desde 6.1 todo lo que hace es evaluar la expresión y luego crear un PageContext en línea con la cadena incluida como código .

Muy resbaladizo, muy eficiente.

Por lo tanto, la manera más sencilla y directa para lograr sus objetivos es:

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

Así que suponiendo que tiene un campo denominado "nombre de usuario", este será el equivalente de llamada siguiente método:

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

y lo que devuelve se asignará a variables.result.

En las pruebas, en realidad supera la técnica de notación de corchetes de reasignación de un método a un nuevo nombre. No tengo estadísticas aquí en este momento pero es más rápido por un margen sustancial porque una inclusión es más rápida (y ocurre en una fase diferente de análisis/compilación) que una asignación variable.

+0

En cuanto a la advertencia de Adán contra evaluar(), aparte de ser estúpido y usarlo para evaluar los valores proporcionados por el usuario (como permitir a los usuarios escribir el código esencialmente, sí, ya está hecho) NO hay razones para evitar el uso de este método. No hay problemas persistentes de rendimiento o seguridad. – jrypkahauer

0

Otra aproximación a este problema es utilizar una UDF como la siguiente:

<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> 

Si necesita usted podría esto:

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

o envolverlo en las etiquetas y tirar en un CFC:

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

hay muchas, mUCHAS maneras de hacer que esto suceda ... acaba de lanzar varias ideas que hay ahora.

Cuestiones relacionadas