PHP - язык c динамической типизацией данных. При динамической типизации данных связывание переменной с ее типом происходит в момент присваивания значения.В переменных PHP можно хранить любые данные, они будут автоматически преобразованы в тот тип, который на данный момент необходим, также в различных участках программы переменной можно присваивать данные различных типов.
Типы данных
В Zend Engine
все типы данных представлены структурой zval
(Zend Value) которая имеет следующие объявление:
struct _zval_struct {
/* Хранимое значение */
zvalue_value value;
/* Счетчик ссылок */
zend_uint refcount__gc;
/* Тип хранимого значения в value */
zend_uchar type;
/* Флаг ссылки на другие данные */
zend_uchar is_ref__gc;
};
typedef struct _zval_struct zval;
В элементе value
хранится данные (значение переменной), value
- объединение, которое объявлено следующим образом:
typedef union _zvalue_value {
long lval; // Элемент для хранения целочисленного значения
double dval; // Элемент для хранения значения с плавающей точкой
struct {
char *val;
int len;
} str; // Элемент для хранения строковых данных
HashTable *ht; // Элемент для хранения хэш-таблиц (массивов)
zend_object_value obj; // Элемент для хранения объектов
} zvalue_value;
Это объединение позволяет хранить данные следующих типов:
Тип данных | Описание |
---|---|
NULL | Данный тип присваивается всем неинициализированным переменным при первом использовании. В пользовательском пространстве данное значение можно присвоить переменной используя константу NULL(null). Данный тип поддерживает специальное неопределенное значение ("non-value"), которое отличается от булевого FALSE и целого 0 |
BOOL | Булева переменная, может иметь одно из двух значений TRUE или FALSE. В пользовательском пространстве булево значение переменной можно присвоить используя константы TRUE и FALSE |
LONG | Целочисленный тип. В PHP целочисленные хранятся в переменной типа signed long языка Си. Это позволяет хранить значения в диапазоне от -2147483648 до `+2147483647` (на 32-х битных системах). Если в переменную записывается число выходящие за диапазон, то тип переменной автоматически преобразуется в DOUBLE |
DOUBLE | Число с плавающей запятой. Для хранения данного типа PHP использует тип signed double языка Си. Данный тип позволяет хранить числа в диапазоне от 2.225x10^-308 до 1.798x10^308 (на 32-х битных системах). На разных системах диапазон может отличаться |
STRING | Тип данных предназначенный для хранения строк. Это наиболее универсальный тип данных в PHP. Для строк выделяется блок памяти достаточный для сохранения всех символов строки и указатель на выделенный участок памяти сохраняется в структуре zvalue_value. Память всегда выделяется на один байт больше требуемой, для символа завершения строки \0. Символ завершения строки всегда добавляется в конец строки, это позволяет безопасно передавать строку для обработки в бинарно не безопасные функции, чтобы в них однозначно можно было определить конец строки. Помимо указателя на строку в структуре также храниться длина строки. Это позволяет безопасно хранить в строках бинарные данные. |
ARRAY | Массив (вектор). Специальный тип-контейнер для хранения переменных других типов. В отличие от языка C в PHP массив может хранить переменные разных типов. В PHP массив – это комплексный набор данных связанных в структуру HashTable. Каждый элемент данной структуры содержит label и data. В пользовательском пространстве PHP для массивов label - это ассоциативный и числовой индекс элемента массива, а data - это данные (zval) которые с этим индексом связанны |
OBJECT | Объект объединяет в себе все свойства ARRAY к которым добавляются методы, магические методы, свойства, область видимости, модификаторы, константы |
RESSOURCE | Данный тип является универсальным и предназначен для трансляции в пользовательское пространство данных которые не могут быть представлены выше перечисленными типами данных. К таким данным относятся хэндл (handle) подключения к базе данных, хэндл curl и т.д. |
Zend Engine
имеет в своем составе набор констант с префиксом IS_*
, которые содержат числовой код типа данных из вышеперечисленной таблицы:
Константа | Тип данных код которых содержится в константе |
---|---|
IS_NULL | NULL |
IS_BOLL | BOOL |
IS_LONG | LONG |
IS_DOUBLE | DOUBLE |
IS_STRING | STRING |
IS_ARRAY | ARRAY |
IS_OBJECT | OBJECT |
IS_RESOURCE | RESOURCE |
Значение вышеперечисленных констант присваивается элементу type
структуры zval
и определяет какой тип данных храниться в элементе value
структуры в данный момент.
Константы объявлены следующим образом:
#define IS_NULL 0
#define IS_LONG 1
#define IS_DOUBLE 2
#define IS_BOOL 3
#define IS_ARRAY 4
#define IS_OBJECT 5
#define IS_STRING 6
#define IS_RESOURCE 7
Пример проверки типа данных хранимых в структуре zval
:
void print_type(zval *var)
{
switch (Z_TYPE_P(var)) {
case IS_NULL:
zend_printf("The variable is NULL");
break;
case IS_BOOL:
zend_printf("The variable is BOOL");
break;
case IS_LONG:
zend_printf("The variable is LONG");
break;
case IS_DOUBLE:
zend_printf("The variable is DOUBLE");
break;
case IS_STRING:
zend_printf("The variable is STRING");
break;
}
}
Получение типа данных (переменной)
Для получения типа данных хранимых, в данный момент в структуре zval
, Zend Engine
предоставляет макросы Z_TYPE_*
(Z_TYPE
, Z_TYPE_P
, Z_TYPE_PP
).
Макрос Z_TYPE
в качестве параметра принимает структуру zval
(не косвенное указание).
Суффикс _P
в имени макроса Z_TYPE
говорит о том, что в качестве параметра макрос принимает указатель на структуру zval
(косвенный указатель), суффикс _PP
в названии макроса Z_TYPE
говорит о том, что в качестве параметра макрос принимает указатель на указатель (косвенный указатель второго уровня)
Конечно не будет ошибкой если для получения типа данных структуры zval
обратиться напрямую к элементу type
и сравнить его значение с константами семейства IS_
:
void print_var_type(zval *var)
{
if (var->type == IS_LONG) {
zend_printf("The variable is of type long");
} else {
zend_printf("Inccorrect type of variable");
}
}
или
void print_var_type(zval *var)
{
switch(var->type) {
case IS_NULL:
zend_printf("The variable is NULL");
break;
....
default:
zend_printf("The variable is of type %d", var->type);
break;
}
}
Данный способ проверки типа данных не рекомендуется использовать, так как никто не даст гарантии, что в будущем тип данных будет храниться в структуре zval
таким же образом. Использование макросов Z_TYPE
дает гарантию сохранения совместимости расширений между версиями PHP.
Выше приведенные примеры должны быть переписаны следующим образом:
void print_var_type(zval *var)
{
if (Z_TYPE_P(var) == IS_LONG) {
zend_printf("The variable is of type long");
} else {
zend_printf("Inccorrect type of variable");
}
}
void print_var_type(zval *var)
{
switch(Z_TYPE_P(var)) {
case IS_NULL:
zend_printf("The variable is NULL");
break;
....
default:
zend_printf("The variable is of type %d", Z_TYPE_P(var->type));
break;
}
}