2013-04-22 3 views
3

Если у меня естьВызов функции с динамическим массивом аргументов

<cfset arr_arguments = ["a","b","c"]> 
<cfunction name="someFunction"> 
<cfargument name="someArgumentOne"> 
<cfargument name="someArgumentTwo"> 
<cfargument name="someArgumentThree"> 

</cffunction> 

Есть ли способ вызвать someFunction с аргументами arr_arguments, похожий на someFunction("a","b","c")? Я, конечно, знаю, что могу использовать argumentCollection, чтобы передать (привязанную) структуру к функции, но я специально спрашиваю о передаче в (без ключа) массива. В JS это можно легко сделать с someFunction.apply(this,arr_arguments), но в coldfusion я просто не могу найти способ сделать это.

+0

Возможно, я неправильно понимаю ваш вопрос или причину требования, но вы могли бы использовать 'someFunction.apply (arrayToList (arr_arguments))' Я никогда не пробовал. – Travis

+0

'someFunction.apply()' является синтаксисом javascript, а не CF. И причина этого требования заключается в том, что аргументы генерируются из внешнего источника без ключа и могут перейти к различным различным функциям, основанным на информации в том же источнике. –

+0

Я не вижу причин, по которым вы не можете передать массив в cffunction, используя '' – Travis

ответ

4

Несущие аргументы передаются в функцию как структуру с числовыми ключами, соответствующими положениям аргументов, определенных в аргументах функции.Поэтому вместо того, передавая именованные аргументы, вы можете преобразовать массив в структуры с помощью цифровых клавиш, а затем передать структуры в с argumentCollection:

<cfset arr_arguments = {"1"="a","2"="b","3"="c"}> 
<cfset someFunction(argumentCollection=arr_arguments)> 

Вы можете легко преобразовать массив в структуры с помощью цифровых клавиш, как это :

<cfset args = {}> 
<cfloop from="1" to="#arrayLen(arr_arguments)#" index="i"> 
    <cfset args[i] = arr_arguments[i]> 
</cfloop> 
1

Хорошо, если вы хотите вызвать функцию с суровым массивом аргументов, лучшим вариантом, который я могу предложить, является создание функции-обертки. Ниже пример кода

<cfscript> 
    function testMe(
     required string arg1, 
     required string arg2 
    ) { 
     writedump(arguments); 
    } 

    function invokeFunction(
     required inFunction, 
     required array functionArguments 
    ) { 
     var stcArguments = {}; 
     // Introspect to get the method parameters 
     var arrFunctionArguments = GetMetaData(arguments.inFunction).parameters; 
     // Now figure out what we are iterating to 
     var numArgumentsToParse = Min(ArrayLen(arguments.functionArguments),ArrayLen(arrFunctionArguments)); 
     // Populate the arguments structure 
     for (var i=1;i<=numArgumentsToParse;i++) { 
      stcArguments[arrFunctionArguments[i].name] = arguments.functionArguments[i]; 
     } 
     // And try to call it 
     return arguments.inFunction(
      argumentCollection = stcArguments 
     ); 
    } 

    invokeFunction(testMe,[1,2]);   // Works fine 
    invokeFunction(testMe,[1,2,3,4]);  // Just skips 3 and 4 
// invokeFunction(testMe,[1]);    // Errors due to not enough arguments 
// invokeFunction(fakeFunctionName,[1]); // Errors due to undefined function 
</cfscript> 

Это будет ошибка, конечно, если выполняется одно из следующих действий произойдет

  • один или несколько аргументов не правильного типа
  • функция фактически не существует
  • Не все необходимые аргументы передаются в

Но вы можете справиться с этим снаружи. Это будет использовать интроспекцию, чтобы определить имена аргументов, заполнить структуру соответствующим образом и вызвать запрошенную функцию.

+0

Если я сейчас понимаю его вопрос, у него есть массив, содержащий значения, которые используются несколькими функциями. Я предполагаю, что функции используют разные имена аргументов, которые мешают ему использовать единую структуру и аргументCollection, и он ищет супер сокращенный способ использования массива в качестве нескольких параметров для нескольких функций. – Travis

+0

Хмм, у меня, возможно, был неправильный конец палки. Это звучит опасно, как случай для Evaluate, насколько я ненавижу использовать это: \ НО У меня есть идея, просто нужно несколько минут –

+0

Ну, причина всего в первую очередь заключается в основе структуры, вроде как codeigniter (но разные). Тем не менее, часть передачи в «аргументах» url в функции различных компонентов контроллера аналогична. Таким образом, источник (например, «controller/page/argument1/argument2») не предоставляет информацию о том, какой параметр является чем-то или что-либо в этом направлении, но как разработчик просто пишет ' do stuff 'определить \ shop \ item \ 3103 действительно естественно. –

1

Вот UDF, которая будет делать это для вас:

<cfscript> 
function test_function(a,b,c){  
    writeOutput("arguments.a"&arguments.a&"<br>"); 
    writeOutput("arguments.b"&arguments.b&"<br>"); 
    writeOutput("arguments.c"&arguments.c&"<br>"); 

    return arguments.a & "::" & arguments.b & "::" & arguments.c; 
} 

function invoke_positional(func,arr){ 
    var metaData = GetMetaData(func); 
    var args={}; 
    for(var pos=1;pos<=ArrayLen(arr);pos++){ 
     args[metaData.parameters[pos].name]=arr[pos]; 
    } 
    return arguments.func(argumentCollection=args); 
} 

data = ["StringOne","StringTwo",22]; 

result = invoke_positional(test_function,data); 

</cfscript> 

<cfoutput> 
<p> 
Returned: #result# 
</p> 
</cfoutput> 

invoke_positional работы, используя метаданные ОДС, чтобы создать именованный набор параметров, а затем использует их argumentCollection =

+0

Помимо того факта, что я отправил эту четверть часа назад, это может привести к ошибке, если в аргументе arr вызывается больше аргументов в аргументе arroke_positional, чем есть аргументы в функции func, поэтому проверка, которую я включил, чтобы предотвратить возникновение. –

+0

Согласен, ваш был первым и имеет более полную запись. Когда я начал писать свой, твое не было, и я не видел его, пока не опубликовал мой. На мой взгляд, вы должны быть приняты. Я возьму мин – barnyr

0

Так, один Опция, которую я обнаружил, заключается в том, чтобы создать объект аргументов отдельно от реальной области реальных аргументов и просто добавить значения к нему с помощью числового индекса.

<cfset args_input = createObject("java","com.naryx.tagfusion.cfm.engine.cfArgStructData").init()> 
<cfloop from="1" to="#arraylen(arr_arguments)#" index="i"> 
    <cfset args_input[i] = arr_arguments[i]> 
</cfloop> 
<cfset someFunction(argumentCollection=args_input)> 

Если вы столкнулись с такой ситуацией, используя Adobe ColdFusion, я бы посоветовал вам попробовать

<cfset correctClass = arguments.getClass().getName()> 

Чтобы получить строку перейти к CreateObject. Или, если это не работает, только есть специальная функция, чтобы возвращать пустой объект аргументов

<cfset args_input = this.generateArgumentObject()> 

и

<cffunction name="generateArgumentObject"> 
    <cfreturn arguments> 
</cffunction> 

Ну да ладно, все, что я знаю наверняка, что он будет работать точно в OpenBD и на основании сообщения, которое я видел в прошлом в блоге Бена Наделя, я вполне уверен, что это должно работать и в Adobe ColdFusion.

+0

Хотя я ценю, что вы знаете, что ищете, не совсем уверен, что я вижу, как это соотносится с вашим собственным вопросом? Также в coldfusion определение структуры должно быть '{test =" test2} 'вместо использования': ' –

+0

.' Args_input' может (в отличие от массива) передаваться прямо в 'argumentCollection', без необходимости проверять соответствующие функция, это делает ее более ясной? –

+0

Обновлен ответ, чтобы сделать его немного понятнее. Конечно, все 3 ответа определенно будут работать, сейчас я искушаюсь использовать это решение, потому что кажется, что он не подходит для проверки функций, хотя это, вероятно, не так дорого, как кажется. Может быть, некоторые тесты, когда у меня есть время, сравнивающее два варианта с eachother. –

2

в Coldfusion 10, вы можете использовать invoke function, чтобы сделать это. По-видимому, это недокументированный способ передать массив аргументов по порядку. Пример в cfscript:

invoke('', 'someFunction', ['a','b','c']); 

Первый аргумент invoke это имя компонента (или пустая строка для UDF). Второй - это имя функции, а третий - массив аргументов. Обратите внимание, что имена компонентов и функций должны передаваться как строки.

Я протестировал это как с именами аргументов, так и без них, и порядок аргументов был сохранен.

+0

Или вариант тега: '