J'essaie de faire en sorte qu'une extension PHP (7.4) utilise dans une méthode d'extension un paramètre de php.ini (comme myext.map=key1=val1,key2=val2;) analysé comme un tableau associatif. Je veux que l'analyse se fasse dans PHP_MINIT_FUNCTION(myext).

J'ai donc déclaré un paramètre php, non commenté REGISTER_INI_ENTRIES(); dans PHP_MINIT_FUNCTION(myext), déclaré :

ZEND_BEGIN_MODULE_GLOBALS(myext)
    HashTable map;
ZEND_END_MODULE_GLOBALS(myext)

Et rempli MYEXT_G(map) à partir du paramètre php.iniJR :

PHP_INI_MH(myext_update_map) {
// The part that parses new_value into (key => val) pairs is skipped. It works.
//...
// key = val assignments have been counted.
zend_hash_init(&MYEXT_G(map), count, NULL, NULL, 1); // 1 for "persistent".
// ...
// Iterating (key => value) pairs.
    // key, key_len, val, val_len have been successfully extracted from php.ini.
    zend_string * key_z = zend_string_init( key, key_len, 1 );
    zval val_z;
    ZVAL_STRINGL( &val_z, val, val_len );
    zend_hash_add_new( &MYEXT_G(map), key_z, &val_z );

Ensuite, dans une méthode PHP, j'essaie de lire les données de &MYEXT_G(map):

PHP_METHOD(MyExt, getMap) {
// ...
zend_string * key_z;
zval * val_z;
ZEND_HASH_FOREACH_STR_KEY_VAL(&MYEXT_G(map), key_z, val_z)
    php_error_docref( NULL TSRMLS_CC, E_WARNING, "ZSTR_VAL(key_z) = %s\n", ZSTR_VAL(key_z) );
    php_error_docref( NULL TSRMLS_CC, E_WARNING, "Z_STRVAL_P(val_z) = %s\n", Z_STRVAL_P(val_z) );
    php_error_docref( NULL TSRMLS_CC, E_WARNING, "Z_STRLEN_P(val_z) = %lu\n", Z_STRLEN_P(val_z) );
ZEND_HASH_FOREACH_END();

Si le script PHP contenant MyExt::getLibraries() est appelé à partir de la ligne de commande, les avertissements PHP affichent les clés et les valeurs telles qu'elles ont été définies dans php.ini.

Cependant, si le script est appelé par requête HTTP, dans les messages d'avertissement, ZSTR_VAL(key_z) est correct mais Z_STRVAL_P(val_z) et Z_STRLEN_P(val_z) contiennent tous les deux des déchets.

Toutes les fonctions impliquées sont soit définies comme des macros PHP, soit reçoivent TSRMLS_DC.

Il semble que les valeurs (mais pas les clés) dans une table de hachage globale soient désallouées entre l'initialisation du module et le service de la requête HTTP.

Je me suis assuré que les valeurs scalaires dans MYEXT_G survivent de PHP_MINIT_FUNCTION(myExt) dans la méthode PHP appelée à partir d'une requête HTTP.

Alors, comment puis-je m'assurer que les valeurs HashTable sont vraiment persistantes ?

0
Alexander Mashin 16 sept. 2020 à 13:15

1 réponse

Meilleure réponse

Comme on m'a conseillé PHP internals (internals@lists.php.net), ZVAL_STRINGL alloue une chaîne par requête ; et j'avais besoin de ZVAL_STR : ZVAL_STR(&val_z, zend_string_init(val, val_len, 1));.

Ensuite, j'ai ajouté val_z à la table de hachage globale : zend_hash_str_add_new( &MYEXT_G(map), key_z, key_len, &val_z );. La table de hachage &MYEXT_G(map) était lisible (à la fois les clés et les valeurs) lors de la diffusion des requêtes HTTP.

0
Alexander Mashin 30 sept. 2020 à 07:15