antonio's blog

antonio's blog


Блог о всяком разном, связанном с разработкой ПО. Пишу редко, когда есть время и желание.

Anton Dobkin
Author

Share


Tags


Разработка расширений для PHP. Константы

Anton DobkinAnton Dobkin

В PHP сценариях константы объявляются с помощью функции define(), которая принимает два параметра: имя константы и ее значение.

Внутри PHP константы объявляются похожим способом.Для объявления константы используются макросы семейства REGISTER_*_CONSTANT(). Большинство констант объявляются один раз в во время инициализации модуля, в PHP_MINIT_FUNCTION()

Макросы семейства REGISTER_*_CONSTANT():

Все макросы в качестве первого параметра принимают строковую литералу с названием константы под которым она будет доступна в пользовательском пространстве.

Макросы семейства REGISTER_*_CONSTANT() для определения длинны имени константы используют вызов sizeof(), поэтому в качестве имени константы допускается использование только строкового литерала, нельзя использовать указатель на строку (char *) так как результат вычисления будет не верен, sizeof( char * ) на 32-х битных системах обычно возвращает 4 — размер, в байтах, указателя на char

Вторым параметром задается значение константы, тип значения зависит от вызываемого макроса соответственно.

Макрос REGISTER_STRINGL_CONSTANT() третьем параметром принимает цело число символов которое будет скопировано из значения переданного во втором параметре.

Последним параметром макросы принимают один из битовых флагов или несколько флагов объеденные побитовым ИЛИ. В качестве битовых флагов принимается константы: CONST_CS — указывает на то что создаваемая константа регистрозависимая. Это правило является принятым по умолчанию для констант объявляемых в пользовательском пространстве и для констант объявляемых внутри PHP. Для некоторых констант, таких как TRUE, FALSE, NULL, это правило не применяется. Данных константы объявлены как регитронезависимые. CONST_PERSISTENT — указывает на то, что константа должно быть доступна между запросами

Если константы объявляется в PHP_MINIT_FUNCTION(), то очевидно, что она должна быть объявлена с флагом CONST_PERSISTENT и она будет доступна между запросами. Когда же константа объявляется при поступлении запроса, в функции PHP_RINIT_FUNCTION(), вы должны опускать данный флаг, позволяя движку уничтожить данную константу в конце запроса.

Примеры объявления констант с использованием макросов семейства REGISTER_*_CONSTANT()

PHP_MINIT_FUNCTION(my_extension)  
{
   REGISTER_STRING_CONSTANT("MY_EXTENSION_CONST", "Value of my extension constant", CONST_CS | CONST_PERSISTENT);
   return SUCCESS;
}

В данном примере объявляется строковая константа, которая будет доступна в пользовательском пространстве под именем MY_EXTENSION_CONST. Константа объявлена как регистрозависимая и будет доступна между запросами, на протяжении всего времени работы модуля. Значение константы будет скопировано в отдельный участок памяти, который будет автоматически освобожден в фазе завершения работы модуля.

Использование константы в пользовательском пространстве:

<?php  
   echo  MY_EXTENSION_CONST; // Выведет  Value of my extension constant
   echo  my_extension_const; // Ошибка! Константа регистрозависимая 
?>

В следующем примере также объявляется строковая константа:

static char *const_value = NULL;

PHP_MINIT_FUNCTION(my_extension) {  
  const_value = (char*)malloc(12);
  strcpy( const_value, "Hello world");

  REGISTER_STRING_CONSTANT("MY_EXTENSION_CONST_2", const_value, CONST_CS | CONST_PERSISTENT);

  return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(my_extension){  
   free(const_value);
}

В примере объявляется указатель const_value на char. Внутри функции PHP_MINIT_FUNCTION() выделяется участок память, в выделенный участок помещается строка "Hello world". Указатель const_value указывает на начало выделенного блока памяти. Далее происходит инициализация константы, которая в пользовательском пространстве будет доступна под именем MY_EXTENSION_CONST_2. Во втором параметре передается не строковая литерала со значением, а указатель на бок памяти в котором содержится значение константы.

Если в качестве имени константы необходимо использовать переменную, в которой хранится название, например, создаваемое в цикле, то макросы семейства REGISTER_*_CONSTANT не могут быть для этого использованы из-за за использования вызова sizeof() для определения длинны имени константы. В таких случаях необходимо использовать следующие функции:

Макросы семейства REGISTER_*_CONSTANT также вызывают выше указанные функции. Первым параметром в функцию передается название константы под которым она будет доступна в пользовательском пространстве, вторым параметром передается длина имени константы. Если для вычисления длинны строки будет использоваться функция strlen(), то к возвращаемому ею значению необходимо прибавить 1, так как функция не учитывает символ завершения строки '\0'. Третьим параметром функции принимают значение константы.

Функция zend_register_string_constant() и zend_register_stringl_constant() четвертым параметром принимают длину строки, указанной в качестве значения. Следующим параметром функции принимают битовые флаги, которые описаны выше. Предпоследним параметром в функции передается переменная module_number- номер модуля. Данная переменная инициализируется движком при загрузке расширения и служит ключом для отчисти данных когда модуль выгружается из памяти. Данная переменная доступна во всех PHP_MINIT_FUNCTION() и PHP_RINIT_FUNCTION(), поэтому просто передавайте её в функции создания констант не задумываясь о её содержимым. Последним параметром должен явно передаваться макрос TSRMLS_CC

Пример создания константы:

PHP_MINIT_FUNCTION(my_extension )  
{
   char *const_name = "MY_EXTENSION_CONST";
   zend_register_string_constant( const_name, strlen(const_name)+1,  "Hello world ", CONST_CS |CONST_PERSISTENT, module_number TSRMLS_CC);
   return SUCCES;
}

Макросы семейства REGISTER_*_CONSTANT и функции семейства zend_register_*_constant() не охватывают все типы констант которые могут понадобиться. В Zend API нет макросов и функций способных, например, создавать константы в качестве которых будет массивы или объекты. Для создания таких констант необходимо использовать функцию zend_register_constant().

Прототип функции:

int zend_register_constant( zend_constant *c, TSRMLS_DC )

В качестве первого аргумента функция принимает инициализированную структуру с информацией о константе, вторым параметром макрос TSRMLS_CC

zend_constant — структура имеющая следующие объявление:

typedef struct _zend_constant {  
   zval value;
   int flags;
   char *name;
   uint name_len;
   int module_number;
} zend_constant;

Поля структуры:

Пример создания константы:

PHP_MINIT_FUNCTION(my_extension )  
{
   char *const_name = "MY_EXTENSION_CONST";
   zend_constant c;

   ZVAL_TRUE( (&c.value);
   c.flags = CONST_CS | CONST_PERSISTENT;
   c.name = zend_strndup(const_name, strlen(const_name ));
   c.name_len = strlen(const_name) + 1 ;
   c.module_number = module_number;

   zend_register_constant(&c; TSRMLS_CC);

  return SUCCES;
}

В данном примере создается константа с булевым значением TRUE

Anton Dobkin
Author

Anton Dobkin

Comments