#pointers #coldfusion #components
#указатели #coldfusion #Компоненты
Вопрос:
У меня возникла проблема с компонентом Coldfusion, который я создаю. Ну, я не совсем уверен, проблема ли это или как все должно работать, но это кажется странным. Сначала я настраиваю аргументы для функции инициализации моего компонента и вызываю компонент. Но если я изменю один из аргументов после вызова, это также изменит значения, хранящиеся в компоненте. Правильно ли это?
Я не уверен, что хорошо это объясняю. Вот некоторый псевдокод:
<cfset fruit = [] />
<cfset fruit[1] = {
id = 1,
name = "apple"
} />
<cfset fruit[2] = {
id = 2,
name = "orange"
} />
<cfset args = {
title = "Fruit",
data = fruit
} />
<cfinvoke component="test" method="init" returnvariable="test" argumentcollection=#args# />
<cfset fruit[2].name = "banana" />
init
Функция сохраняет аргументы title
и data
в variables
области видимости компонента.
Теперь, если я вывожу данные из test
объекта, я получаю apple
и banana
. Но я ожидал, что компонент сохранит данные, которые он получил во время вызова.
Дайте мне знать, если мне нужно что-нибудь уточнить. Спасибо за любую помощь!
Ответ №1:
Я не совсем уверен, является ли это проблемой или как все должно работать,
Да, именно так должен работать ваш текущий код. Независимо от того, хотите ли вы, чтобы это вело себя так, это другой вопрос ..
Большинство сложных объектов (структур, компонентов и т. Д.) Передаются по ссылке. Это означает, что вы, по сути, просто сохраняете указатель на объект, а не фактические значения. Таким образом, вы всегда будете видеть любые изменения, внесенные в базовый объект. Вот почему выходные данные test
изменяются.
Массивы являются исключением. Обычно (хотя и не всегда) они передаются по значению. Это означает, что у вас есть независимая копия, которая не будет отражать никаких изменений, внесенных в исходный объект.
Ваш пример интересен, потому что он содержит оба. Изменения в ваших вложенных структурах ( name=orange
=> name=banana
) видны в компоненте, поскольку структуры передаются по ссылке. Но родительский массив таковым не является. Таким образом, вы могли бы очистить fruit
, и это не повлияло бы на компонент.
Пример:
<cfset fruit[2].name = "bananna" />
<!--- both dumps will show "bananna" --->
<cfdump var="#fruit#" label="Fruit Before" />
<cfdump var="#test.getDataArray()#" label="Test.Data Before" />
<cfset arrayClear(fruit) />
<!--- fruit is empty and the component array is not --->
<cfdump var="#fruit#" label="Fruit After" />
<cfdump var="#test.getDataArray()#" label="Test.Data After" />
Тест:
<cfcomponent>
<cffunction name="init" returntype="any" ...>
<cfargument name="title" type="string" required="true" />
<cfargument name="data" type="array" required="true" />
<cfset variables.title = arguments.title />
<cfset variables.data = arguments.data />
<cfreturn this />
</cffunction>
<cffunction name="getDataArray" returntype="array">
<cfreturn variables.data />
</cffunction>
</cfcomponent>
Теперь, если я вывожу данные из тестового объекта, я получаю яблоко и банан.
Правильно. Этого и следовало ожидать, поскольку структуры передаются по ссылке. Если вы хотите, чтобы компонент сохранял независимую копию, вам необходимо duplicate()
(т.Е. Глубоко скопировать) data
элемент внутри init()
.
<cfset variables.data = duplicate(arguments.data) />
Ответ №2:
В то время как массивы передаются по ЗНАЧЕНИЮ в ColdFusion, даже объекты внутри них. Если вы хотите сохранить значения в функции, верните массив, который обновляет ваша функция инициализации, и установите для вашего фруктового массива значение, равное этому.
У меня была бы функция получения, которая возвращала бы ваш массив:
<cffunction name="getArray" returntype="array" access="public" output="false" hint="return the array" >
<cfreturn variables.theArray>
</cffunction>
И в вашем шаблоне cfm вы бы установили свой фруктовый массив равным этому значению:
<cfset fruit = test.getArray()>