How to Define Persistent Constants in a PHP 7.x Extension
This article explains step‑by‑step how to add, register, and correctly clean up persistent constants in a PHP 7.x extension, covering the necessary macro calls, hash‑destroy functions, and a common fatal‑error pitfall with its solution.
In PHP extensions you can define constants just like in scripts, but the process differs when you need persistent constants that survive across requests. This guide shows how to add three constants—an array, a string, and a namespaced string—inside the PHP_MINIT_FUNCTION of a custom say extension.
Adding the code
// destroy a hash table
static void say_hash_destroy(HashTable *ht) {
zend_string *key;
zval *element;
if ((ht->u.flags & HASH_FLAG_INITIALIZED)) {
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, element) {
if (key) {
free(key);
}
switch (Z_TYPE_P(element)) {
case IS_STRING:
free(Z_PTR_P(element));
break;
case IS_ARRAY:
say_hash_destroy(Z_ARRVAL_P(element));
break;
}
} ZEND_HASH_FOREACH_END();
free(HT_GET_DATA_ADDR(ht));
}
free(ht);
}
// destructor for persistent entries
static void say_entry_dtor_persistent(zval *zvalue) {
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
say_hash_destroy(Z_ARRVAL_P(zvalue));
} else if (Z_TYPE_P(zvalue) == IS_STRING) {
zend_string_release(Z_STR_P(zvalue));
}
}
PHP_MINIT_FUNCTION(say) {
zend_constant c;
zend_string *key;
zval value;
ZVAL_NEW_PERSISTENT_ARR(&c.value);
zend_hash_init(Z_ARRVAL(c.value), 0, NULL, (dtor_func_t)say_entry_dtor_persistent, 1);
add_index_long(&c.value, 0, 2);
key = zend_string_init("site", 4, 1);
ZVAL_STR(&value, zend_string_init("www.bo56.com", 12, 1));
zend_hash_update(Z_ARRVAL(c.value), key, &value);
c.flags = CONST_CS|CONST_PERSISTENT;
c.name = zend_string_init("__ARR__", 7, 1);
c.module_number = module_number;
zend_register_constant(&c);
REGISTER_STRINGL_CONSTANT("__SITE__", "www.bo56.com", 12, CONST_PERSISTENT);
REGISTER_NS_STRINGL_CONSTANT("say", "__SITE__", "bo56.com", 8, CONST_CS|CONST_PERSISTENT);
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(say) {
zval *val = zend_get_constant_str("__ARR__", 7);
say_hash_destroy(Z_ARRVAL_P(val));
ZVAL_NULL(val);
return SUCCESS;
}Code explanation
Only a few constant types (null, bool, long, double, string) are supported by the kernel; the macros for defining them reside in Zend/zend_constants.h. For strings you can use REGISTER_STRINGL_CONSTANT, and for namespaced strings the macro REGISTER_NS_STRINGL_CONSTANT where the first argument is the namespace.
The last parameter of these macros contains flags: CONST_PERSISTENT makes the constant live in persistent memory, and CONST_CS makes it case‑sensitive. Note the case difference between the defined name __SITE__ and the lookup name __site__.
Common error and fix
When the extension is unloaded, Zend’s internal destructor tries to free the persistent array and reports a fatal error:
Fatal error: Internal zval 's can’t be arrays, objects or resources. The fix is to manually destroy the array in PHP_MSHUTDOWN_FUNCTION before Zend’s destructor runs, as shown in the shutdown code above.
After applying this change, the extension compiles and runs without the fatal error, and the defined constants are available throughout the request lifecycle.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
