Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions tip_dannih_zval/privedenie_tipov_i_operatsii.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Приведение типов и операции

##Базовые операци
##Базовые операции

Так как zval-ы это комплекстные значения вы не можете напрямую выполнять над ними такие операции как `zv1 + zv2`. Если вы попробуете выполнить что-то подобное, то либо получите ошибку, либо получите сложение двух указателей, а не их значений.

Expand Down Expand Up @@ -44,9 +44,9 @@ int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); /* < */
int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); /* <= */
```
Все функции принимают в качестве аргумента zval `result`, в которой будет сохранен результат операции над операндами `op1` и `op2`. Результат возвращаемый функциями (`SUCCESS` или `FAILURE`) сообщает о том была операция произведена успешно или нет. Помните, что переменной `result` всегда устанавливается какое-то значения, вне зависимости от того успешно завершилась операцция или нет.
Все функции принимают в качестве аргумента zval `result`, в которой будет сохранен результат операции над операндами `op1` и `op2`. Результат возвращаемый функциями (`SUCCESS` или `FAILURE`) сообщает о том была операция произведена успешно или нет. Помните, что переменной `result` всегда устанавливается какое-то значения, вне зависимости от того успешно завершилась операция или нет.

Переменной `result` должна быть выделена память и она должна быть инициализирована перед вызовом одной из перечисленных выше функций. Как альтенатива, переменные `result` и `op1` могут быть одной и той же переменной, в таком случае будет выполнена эффективная операция составного присваивания:
Переменной `result` должна быть выделена память и она должна быть инициализирована перед вызовом одной из перечисленных выше функций. Как альтернатива, переменные `result` и `op1` могут быть одной и той же переменной, в таком случае будет выполнена эффективная операция составного присваивания:
```c
zval *a, *b;
MAKE_STD_ZVAL(a);
Expand Down Expand Up @@ -121,7 +121,7 @@ int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
```
Еще раз подчеркнем: все функции принимают на вход 2 операнда, zval `result`, в который будет записан результат и возвращают `SUCCESS`/`FAILURE`.

Функция `compare_function()` выполняет "обычное" в терминах PHP сравнение (то естбь ведет себя так же как и операторы `<`, `>` и `==`)performs a “normal” PHP comparison (i.e. it behaves the same way as the <, > and == operators). Функция `numeric_compare_function()` сравнивает операнды как числа (первым делом приводя их типы к double).
Функция `compare_function()` выполняет "обычное" в терминах PHP сравнение (то есть ведет себя так же как и операторы `<`, `>` и `==`)performs a “normal” PHP comparison (i.e. it behaves the same way as the <, > and == operators). Функция `numeric_compare_function()` сравнивает операнды как числа (первым делом приводя их типы к double).

Функций `string_compare_function_ex()` сравнивает операнды как строки и меет флаг отвечающий за то должны ли строки сравниваться без учета регистра букв. Также, вместо того чтобы задавать этот флаг вы можете воспользоваться функциями `string_compare_function()` (регистрозависимое сравнение) или `string_case_compare_function()` (регистронезависимое сравнение). Переменные сравниваются этими функциями как обычные строки без дополнительной магии для чисел представленных как строки.

Expand All @@ -131,7 +131,7 @@ int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)

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

Для поддержки системы динамических типов вам следует преобразовывать ваши zval-ы к тем типам, с которыми вы собираетесь работать. Для этой цели PHP поедрставляет функции `convert_to_*` для каждого типа (кроме ресурсов, так как не существует тайп кастинга (resource)):
Для поддержки системы динамических типов вам следует преобразовывать ваши zval-ы к тем типам, с которыми вы собираетесь работать. Для этой цели PHP представляет функции `convert_to_*` для каждого типа (кроме ресурсов, так как не существует тайп кастинга (resource)):
```c
void convert_to_null(zval *op);
void convert_to_boolean(zval *op);
Expand Down Expand Up @@ -205,7 +205,7 @@ php_printf("%ld\n", Z_LVAL_PP(zv_dest));

/* Деструктор не нужен так как аргументы функций уничтожаются автоматически */
```
Использование `convert_to_long_ex()` в примере выше предотвратит модификацию ссылок на значение снаружи массива, но все равно поменяет значение внутри массива. Иногда это приемлемое поведение, но чаще вы захотите избежать изменения элементовмассива при извлечении значений из него.
Использование `convert_to_long_ex()` в примере выше предотвратит модификацию ссылок на значение снаружи массива, но все равно поменяет значение внутри массива. Иногда это приемлемое поведение, но чаще вы захотите избежать изменения элементов массива при извлечении значений из него.

В таких случаях нет другого варианта кроме как копировать zval перед преобразованием типа:
```c
Expand All @@ -221,7 +221,7 @@ php_printf("%ld\n", Z_LVAL(tmp_zv));

zval_dtor(&tmp_zv);
```
Последний вызов `zval_dtor()` в коде выше необязателен, так как мы знаем, что`tmp_zv` будет иметь тип `IS_LONG`, а он не требует обязательного вызова деструктора. Для преобразования других типов, такх как строки или массивы, вызов деструктора необходим.
Последний вызов `zval_dtor()` в коде выше необязателен, так как мы знаем, что`tmp_zv` будет иметь тип `IS_LONG`, а он не требует обязательного вызова деструктора. Для преобразования других типов, таких как строки или массивы, вызов деструктора необходим.

Если в вашем коде часто встречаются преобразования в тип long или в тип double, то вам имеет смысл создать функции хелперы, которые будут делать преобразование без модификации zval-а. Вот пример такой функции для преобразования в тип long:
```c
Expand Down Expand Up @@ -256,7 +256,7 @@ long lval = zval_get_long(*zv_dest);

php_printf("%ld\n", lval);
```
Стандартная библиотека PHP уже содержит одну функцию такого типа, она называется [`zend_is_true()`](https://github.com/php/php-src/blob/ccf863c8ce7e746948fb060d515960492c41ed27/Zend/zend_execute_API.c#L446). Эта функция является функциональным эквивалентом приобразования к типу bool, в котором значение возвращается напрямую:
Стандартная библиотека PHP уже содержит одну функцию такого типа, она называется [`zend_is_true()`](https://github.com/php/php-src/blob/ccf863c8ce7e746948fb060d515960492c41ed27/Zend/zend_execute_API.c#L446). Эта функция является функциональным эквивалентом преобразования к типу bool, в котором значение возвращается напрямую:
```c
zval *zv_ptr;
MAKE_STD_ZVAL(zv_ptr);
Expand Down