Modifier un fichier ini en php
Par Laurentj le lundi, mars 29 2010, 17:00 - Projets - Lien permanent
J'aime bien utiliser les fichiers ini pour tout ce qui est configuration. En php, c'est très rapide à charger avec la fonction parse_ini_file (beaucoup plus rapide qu'un fichier de conf en php, avec un facteur 10 je crois), et puis c'est très simple à modifier, la syntaxe étant minimaliste.
C'est pourquoi j'utilise des fichiers ini dans jelix, et pas des trucs du genre yaml, syntaxe que je trouve hyper compliquée [1], en tout cas trop pour l'utiliser pour un fichier de conf [2].
Dans Jelix, il y a des outils pour le développeur pour l'aider à construire son appli, et il arrive donc que ces outils aient à modifier un fichier ini. J'avais fait une première implémentation naïve dans une classe, jIniFile permettant d'enregistrer un fichier ini : une méthode pour lire (avec parse_ini_file), une autre pour écrire en lui passant un tableau de clés/valeurs, et le nom du fichier.
Problème de cette classe : on perd tous les commentaires et les sauts de lignes à la lecture avec parse_ini_file. C'est assez fâcheux pour un fichier de configuration, où les commentaires peuvent être nécessaires.
D'où une autre classe jIniFileModifier, qui permet de charger, modifier et enregistrer un fichier ini, sans perdre les commentaires et les espacements. Elle permet même de supprimer une clé/valeur, avec le commentaire qui lui est associé (le commentaire qui la précède). Cette classe supporte les sections et les tableaux de valeurs. En fait, j'ai fait en sorte qu'elle soit compatible au maximum avec le format ini utilisé par parse_ini_file[3].
Vous pouvez l'utiliser seule dans vos projets, elle est totalement indépendante de Jelix. Par contre, ne l'utilisez pas pour une simple lecture, ce n'est pas son objectif principal, parse_ini_file est beaucoup plus performante pour ça.
Notes
[1] pour preuve : la spécification YAML : 77 pages A4, celle du XML : 30 pages...
[2] si j'avais à choisir un format pour stocker des options de manière arborescente, je choisirais json
[3] il y a en effet quelques variantes, suivant les logiciels
Commentaires
C'est marrant, j'ai eu le même problème pour tout autre chose. Il y avait aussi autre chose qui ne passait pas (je ne suis plus dedans). Du coup, j'ai aussi fait ma classe.
T'es passé à la triple heure et demie d'été ?
09:05 au lieu de 06:35 ;-) Le soleil doit se coucher tard en juin :-D
l'heure du serveur est en effet pas à jour...
Mais c'est désormais corrigé :-)
Sympa.
La classe jException est référencé une fois (dans le constructeur). Ca n'est donc pas "totalement" indépendant de Jelix ;)
Tant qu'on est dans le constructeur, je suis en train de me dire que d'utiliser directement file() plutôt que preg_split+file_get_contents serait probablement plus judicieux.
Pour mes projets (qui se font rares en php) j'ai tendance à écrire mes fichiers de configuration directement dans le format php sous forme de array(). Difficile de faire plus rapide niveau chargement. C'est du PAN en quelque sorte (PHP Array Notation ;)
>La classe jException est référencé une fois
Ah oui mince..
>utiliser directement file() plutôt que preg_split+file_get_contents serait probablement plus judicieux
Probable en effet. je crois que c'est un oubli de l'existence de cette fonction file :-)
>j'ai tendance à écrire mes fichiers de configuration directement dans le format php sous forme de array(). Difficile de faire plus rapide niveau chargement.
Si, justement comme je l'ai dis, le chargement des fichiers ini est beaucoup beaucoup plus rapide que le chargement d'un fichier PHP. C'est une question de parser. Celui de PHP doit tenir compte de beaucoup plus de symbole et de particularité syntaxique que le parser INI. J'ai fais des benchs, il n'y a pas photo, charger un fichier de conf en ini est 10 fois plus rapide (à peu prés) que de charger un fichier de conf php.
@laurentj
Même avec APC ? Pas sur... Bon, je dis ça, je n'ai pas fait de benches. De toute manière, un tel format à base de array() est read only, ça n'est donc pas la même chose que du .ini en read+write. Bon, parse_ini_file est read only..
Je me dis qu'il faudrait que je teste la sérialisation/unsérialisation de array (pour la mise en cache). Là je vois mal comment le scanner/parser pourrait être plus complexe que celui du format .ini.
au niveau perf, je parlais de parse_ini_file bien sûr (pas de ma classe). Pour un bench comparant avec APC faut vérifier. Et dans jelix, les fichiers ini sont convertis en php quand il y a APC d'activé. Ce qui est finalement jamais le cas chez les hébergeurs. C'est pourquoi j'ai choisi le ini.
Que ton code soit un simple array ou pas, le lexer PHP reste le lexer PHP. Il doit tenir compte de toute la syntaxe PHP. à noter que le lexer ini natif et le lexer php sont générés tous les deux à partir de YACC.
Oui, le parser ini est basé sur YACC (j'ai vérifié hier). Faudrait que je me motive pour relancer mon attirail php et faire des benches, notamment la serialisation.
Discussion sur la perf des .ini vs le reste intéressante... Parce que c'est vrai que le parsage des fichiers de conf en général c'est quand même le truc qui pose le plus de problème dans une appli, le plus consommateur... Sans parler de l'impossibilité de mettre cette conf en cache mémoire :-)
Franchement, la perf du parsage d'un fichier de conf qui doit pas dépasser 200 lignes... Je te reconnais bien là jyjy. Je suis pas sur que le choix du format du fichier de conf soit lié à un quelquonque souci de perf du format de lecture au final. Ca doit représenter même pas 0,1% du temps d'exec de ta page... Mais ya fallu que tu ajoutes un appel un troll avec "(beaucoup plus rapide qu'un fichier de conf en php, avec un facteur 10 je crois)"
J'avoue que si j'avais eu un peu de temps, je prenais la perche tendue pour me lancer, mais bon j'ai déjà passé trop de temps sur ton blog durant ma pause déjeuner, faut que je m'y remettes!
Bonne continuation!
>Ca doit représenter même pas 0,1% du temps d'exec de ta page
peut-être bien. mais c'est avec un discours comme ça qu'on arrive à faire un bloatware. Quand on veut un framework performant, il faut optimiser à tout les niveaux. Les petits ruisseaux font les grandes rivières, tant au niveau de l'exécution globale d'une action, qu'au niveau de la charge d'un serveur.
0.1% sur une requête, ce n'est rien. 0.1% sur des dizaines de requêtes simultanées, ça commence à faire. 0.1% d'ailleurs qui peuvent devenir 0.2, 0.5 et peut être bien plus encore en fonction de la charge, car ici c'est une opération de lecture de fichier, et comme chacun sait, le système de fichier peut être un goulet d'étranglement quand il est fortement soumis (avec donc des temps d'accès qui augmentent de manière plutôt exponentiel que linéaire).
Jyjy... Tu connais un développeur qui est capable de faire une appli avec un temps de chargement de la conf complétement énorme, et qui par ailleurs est une star dans l'écriture de son code métier ?
Si on veut gagner du temps on passe TOUJOURS d'abord sur la partie métier de son code. Je peux te dire pour l'avoir vécu, que les réflexions du genre 'on peut gagner un facteur 10 sur le chargement de la conf', mène au bloatware... J'ai un jour expliqué à quelqu'un que le foreach php dans certains cas est super lent (genre facteur 2 à 5, même pas 10), et qu'il vaut mieux faire un for avec un $i qui se décrémente dans la boucle. Et ça pour corriger une boucle foreach avec 10000 itérations.
2 jours après, je repasse, ledit code corrigé... Et une équipe de dev complète avec comme instruction de réécrire tous les foreach du code. Et ben excuse moi, mais la différence de gain sur une boucle de 10 iterations était peanut de chez peanut, et en plus dans 95% des cas, poser un for a alourdi la compréhension du code, voir allourdi le code tout court dans certains autres cas.
J'ose pas imaginer le résultat si tu avais été lui expliquer qu'il fallait faire la conf en .ini à cette personne :-)
Bref... Si tu penses une solution propre de chargement de fichier de conf, quelque soit la methode choisie tu t'en sortira. J'ai vu des applis qui chargeait la conf en xml bien faite... Je reste persuadé que ça vaut une solution de conf à base d'ini mal gaulé. Quand au problème de perfs, tu sais par où je suis passé cher ami. Et je pense en toute modestie, que la charge sur un serveur je sais ce que ça veut dire, contrairement à 99,9% des developpeurs... Et partout où je suis passé ce qu'il fallait optimiser c'était jamais des points de détails, et surtout pas la conf. Dans 99% des cas c'était les accès aux BDDs, où aux applis connexes.
Mais bon encore une fois, c'est que mon avis, basé sur mon expérience. De plus je n'ai jamais dis que tu n'avais pas de bonnes raisons de choisir les fichiers ini, mais je maintiens que présenter un 'facteur 10' comme déterminant dans le choix, c'est un appel au troll ;-)