|
Рано или поздно вам понадобится присвоить содержимое одного zval-контейнера другому. Это легче
сказать, чем сделать, так как zval-контейнер содержит не только информацию о типе, но и ссылки на места во
внутренних данных Zend. Например, в зависимости от своих размеров, массивы и
объекты могут быть вложены в большое количество вхождений хэш-таблицы.
Присваивая один zval другому, вы исключаете дублирование вхождений хэш-таблицы, используя только одну ссылку на неё.
Для копирования сложных видов данных используйте конструктор copy.
Конструкторы сopy обычно определяются в языках, поддерживающих перегрузку
операций для копирования сложных/комплексных типов. Если вы определяете объект
в таком языке, у вас имеется возможность перегрузить/overloa операцию "=",
которая обычно отвечает за присвоение содержимого левого значения/lvalue (результата
вычисления левой части операции) правому значению/rvalue (то же самое с правой стороны).
Перегрузка означает присвоение другого значения данной операции и обычно
используется для присвоения вызова функции данной операции. В любом месте
программы, где эта операция используется с таким объектом, эта функция будет
вызываться с lvalue и rvalue в качестве параметров. Снабжённая этой
информацией, она может выполнить операцию предназначенную для операции "="
(обычно расширенную форму копирования).
Такая же форма "расширенного копирования" необходима для zval-контейнеров РНР. Итак, в случае с массивом это расширенное копирование
предполагает воссоздание всех вхождений хэш-таблицы, относящихся к данному
массиву. Для строк должно гарантироваться выделение соответствующей памяти, и т.д.
Zend поставляется с такой функцией, zend_copy_ctor() (предыдущим PHP-эквивалентом была
pval_copy_constructor()).
Наиболее известной демонстрацией является функция, принимающая сложный тип как
аргумент, модифицирующая его, а затем возвращающая аргумент:
zval *parameter;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶meter) == FAILURE)
return;
}
// здесь модифицируйте parameter
// теперь мы возвращаем модифицированный контейнер:
*return_value == *parameter;
zval_copy_ctor(return_value); |
Первая часть функции это запрос аргумента. После (left out) модификации,
однако, становится уже интересно: Контейнер для parameter присваивается контейнеру
(предопределённому) return_value. Теперь, чтобы эффективно дублировать содержимое, вызывается конструктор copy.
Конструктор copy работает непосредственно с предоставленным аргументом, и
стандартными return-значениями являются FAILURE при неудаче и SUCCESS при успехе.
Если в этом примере опустить вызов конструктора copy, и parameter, и return_value
будут указывать на одни и те же внутренние данные, что означает, что return_value будет недопустимой дополнительной ссылкой на те же самые структуры данных. Где
бы ни возникли изменения в данных, на которые указывает parameter, return_value может быть изменено. Таким образом, чтобы создать разные копии, обязан
использовать конструктор copy. Компаньон конструктора copy в Zend API, деструктор zval_dtor(), выполняет противоположные конструктору действия.
| |