Intercepter un require_once [Résolu]

Signaler
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
-
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
-
Hello,


je bloque rarement au point de poser une question, mais là...je ne parviens pas à mes fins et j'ai épuisé mes idées ;-)


La problématique est relativement simple :
je travaille sur un bug connu de mon script de documentation.
Le principe pour documenter des classes est simple : le fichier dans lequel se trouve la classe est choisi, et je fais un require_once dessus. Jusque là, tout va bien. Mais comme mon script remonte les classes héritées, j'ai dû faire un require_once sur toutes les classes uploadées, car, sans règle de nommage, je n'ai pas de moyen de savoir dans quel fichier se trouve la classe héritée.
Ca marche très bien (tant qu'on a pas 200 fichiers uploadés, évidemment, mais ça, c'est un autre problème) quand le fichier de la classe héritée se trouve "au-dessus", ou "avant" le fichier de la classe héritante dans le répertoire.
Mais si elle est après, le require_once du fichier de la classe héritante me sort évidemment une erreur, car il ne trouve pas la aclasse héritée (normal, elle n'a pas encore été incluse).


J'ai donc fait plusieurs tests :
@require_once ne plante plus, mais bloque par contre (évidemment, pas de message d'erreur, mais ça bloque quand même au require défaillant).
J'ai alors testé ça :

<?php
$aDocs = scandir ('classes');
$aFlag = array_fill (0, count ($aDocs) - 1, 0);
while (in_array (0, $aFlag)) {
foreach ($aDocs as $clef => $obj) {
if ($obj !== '.' && $obj !== '..') {
try {
require_once ('classes/'.$obj);
$aFlag[$clef] = 1;
} catch (Exception $e) {
continue;
}
}
}
}
?>


Le but étanht de flagger les fichiers inclus, et, si on rencontre un problème lors d'une inclusion, on saute et on passe aau suivant. Et on reboucle tant que tous les fichiers n'ont pas été flaggés à 1.
Mais rien à faire, le require_once plante, même dans le bloc du try {}.


J'ai ensuite utilisé la bufferisation de sortie :


<?php
$contents = '';
$aDocs = scandir ('classes');
$aFlag = array_fill (0, count ($aDocs) - 1, 0);
while (in_array (0, $aFlag)) {
foreach ($aDocs as $clef => $obj) {
if ($obj !== '.' && $obj !== '..') {
try {
ob_start ();
require_once ('classes/'.$obj);
$aFlag[$clef] = 1;
$contents .= ob_get_contents ();
ob_end_clean ();
} catch (Exception $e) {
continue;
}
}
}
}
echo $contents;
?>


Mais pareil, le require_once plante lamentablement.
Idem avec un @, je précise.


Je me suis alors lancé dans un $contents .= get_file_contents (...) à la place du require_once (), et un eval à la fin (voui je sais...mlais j'étais désespéré)
Mais là, ça tourne carrément trop longtemps au niveau du file_get_contents (je ne parle donc même pas du eval...).


Et là, je n'ai plus d'idée...
Alors si quelqu'un en avait une!! ;-)


Merci :-)

33 réponses

Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
Salut malalam.

Problème interessant... Je vais essayer de te donner une piste pour te décoincer (je dis bien "essayer").

Je pense que l'idée du scandir est bonne... mais pas assez exploitée.

C'est à dire, au lieu de charger (require_once) tous les fichiers contenant des classes, je te propose de plutôt parser ces fichiers.

Par exemple :
* Tu ouvre le répertoire du projet à documenter

* Tu parcours récurssivement le projet, soit tous les fichiers de type texte =>
preg_match('@^text/@',mime_content_type($file));

* enfin tu parses chacun de ces fichiers pour trouver des définition de classes
$content = file_get_contents($file);
if( preg_match_all('@class\s+([\w\d_]+)\s+(extends\s+([\w\d_]+)\s+)?{@im',$content,$res) ) {
/* ici, tu retrouve les classes et leur héritage dans $res */
$file; // le fichier qui contient des définitions de classes
$res[1]; // les noms des classes définies
$res[3]; // les classe parentes de ces dernières
}


* Avec ces infos, tu te construis un tableau, un arbre, des objets, ... tout ce que tu veux pour ensuite pouvoir le parcourir et retrouver facilement les fichier à inclure pour tel ou tel héritage.

Voilà, je ne pense pas que cette passe de parsing soit trop longue et 'espère que ça pourra t'aider...

A+ et bonne chance
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Bon vlà le résultat qui fonctionne à merveille :

<?php
if (isset ($_POST['documenter']) && $_POST['documenter'] === $oloc -> getMsg ('gui', 'app_document') && !empty ($_POST['objet']) && !empty ($_POST['nom'])) {
$aDocs = scandir ('classes');
foreach ($aDocs as $clef => $obj) {
if ($obj !== '.' && $obj !== '..') {
$content = file_get_contents ('classes/'.$obj);
if( preg_match_all([mailto:'@class\s+([\w\d_]+)\s+((extends|implements)\s+([\w\d_]+)\s+)?{@im',$content,$res '@class\s+([\w\d_]+)\s+((extends|implements)\s+([\w\d_]+)\s+)?{@im',$content,$res])) {
$aHierarchy[$res[1][0]]['parent'] = $res[4][0];
$aHierarchy[$res[1][0]]['file'] = $obj;
}
}
}
$className = $_POST['nom'];
$aIncs[] = $aHierarchy[$className]['file'];
while (!empty ($aHierarchy[$className]['parent'])) {
$className = $aHierarchy[$className]['parent'];
$aIncs[] = $aHierarchy[$className]['file'];
}
$aIncs = array_reverse ($aIncs);
foreach ($aIncs as $files) {
require_once ('classes/'.$files);
}
}
?>

Meci à J_G, et à Anthomicro :-)
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Voilà, le code complet :

if (isset ($_POST['documenter']) && $_POST['documenter'] === $oloc -> getMsg ('gui', 'app_document') && !empty ($_POST['objet']) && !empty ($_POST['nom'])) {
$aDocs = scandir ('classes');
foreach ($aDocs as $clef => $obj) {
if ($obj !== '.' && $obj !== '..') {
$content = file_get_contents ('classes/'.$obj);
if( preg_match_all([mailto:'@class\s+([\w\d_]+)\s+((extends|implements)\s+([\w\d_]+)\s+)?{@im',$content,$res '@class\s+([\w\d_]+)\s+((extends|implements)\s+([\w\d_]+)\s+)?{@im',$content,$res])) {
foreach ($res[1] as $clef => $val) {
$aHierarchy[$res[1][$clef]]['parent'] = $res[4][$clef];
$aHierarchy[$res[1][$clef]]['file'] = $obj;
}
}
}
}
$className = $_POST['nom'];
$aIncs[] = $aHierarchy[$className]['file'];
while (!empty ($aHierarchy[$className]['parent'])) {
$className = $aHierarchy[$className]['parent'];
$aIncs[] = $aHierarchy[$className]['file'];
}
$aIncs = array_reverse ($aIncs);
foreach ($aIncs as $files) {
require_once ('classes/'.$files);
}


try {
$doc = new odocclass ($_POST['nom']);
$sError = $oloc -> getMsg ('gui', 'app_document_created').$_POST['objet'];
//header ('Location: docs/'.$_POST['nom'].'/'.$_POST['nom'].'.html');
} catch (Exception $e) {
$sError = $oloc -> getMsg ('errors', 'failed_instance');
}
}
Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
Ouai non... Ca change rien.

Le préprocesseur va un peu plus galérer dans la première version. Mais une fois le script pré-maché (c'est à dire uniquement la première fois qu'il est exécuté) c'est quasiment pareil.

Note : Il y'a un risque de bug avec la RegExp...
class salut{/*...*/} ne colle pas et pourtane elle est bien déclarée ! (=> il n'y a pas d'espace entre le nom et l'accolade)
Correction proposée :
[http:// class\s+([\w\d_]+)(\s+(extends|implements)\s+([\w\d_]+))?\s*{]

A+
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Hello J_G,

j'avais pensé au parsing en effet, mais je pensais que ce serait trop long et fastidieux...ceci dit, vue que je me retrouve bien coincé là...et que ce que tu me montres est plus abouti que ce à quoi j'avais pensé, je vais tenter le coup.
Ca permettrait en plus de résoudre le problème des require inutiles.

Donc, je teste ça de suite :-) Merci J_G!
Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
De rien... surtout que je te laisse le plus dur à faire :

La structure du tableau/arbre à parcourir et les fonction de parcours. Ces exercices algorithmiques sont mes pire casses-têtes.

A+
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Je suis dessus lol...je réflêchis à la meilleure structure pour avoir un arbre facile à remonter. Et effecivement, ce sont les pires casse-têtes :-( Mais c'est rigolo!
J'ai ajouté implements dans ton pattern au fait, comme choix entre exteneds et implements (pour les interfaces).
Et sinon, ton pattern marche à merveille :-)
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Bon, l'acceptation ne marche pour le moment pas, alors j'accepterai la réponse plus tard :-)
Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
Bravo...
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Bah j'ai pas de mérite lol, tu m'as mâché tout le travail :-)
Antho m'a aidé à comprendre pq mon pattern marchait mal (en fait, il marchait très bien, j'avais juste oublié que les offset bougeaient...).
Quant à la hiérarchie, ça a finalement été très simple, comme tu peux le voir :-)
Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
Oui, c'est pour ça que je dis "bravo"... je ne le voyais pas si simple.

Par contre, j'ai l'impression que tu ne prends pas en compte le fait qu'il puisse y avoir plusieur définition de classe dans un même fichier. Par exemple parent + enfant.

C'est pour ça que je t'ai indiqué le preg_match_all

Voilou.
A+
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
C'est exact lol. Mais c'est pas un problème. Je dois juste modifier la façon de construire le tableau hiérarchique c'est tout. Je vais le faire de ce pas d'ailleurs ;-)
Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
Ben super... c'était pas grand chose :)

Et niveau timing : correct ?
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Très, aucun problème contrairement à ce que je pensais.
Tu avais raison :-) Je n'ai pas fait de bench pour comparer, mais disons qu'à l'oeuil nu, on ne voit aucune différence avec avant. De plus, avec ton système, les pages vont être bcp plus légères même avec bcp de classes uploadées, puisqu'on inclut plus que les classes à analyser :-) Donc c'est bien mieux qu'avant ! :-)

Je pourrais remplacer
$aHierarchy[$res[1][$clef]]['parent'] = $res[4][$clef];
$aHierarchy[$res[1][$clef]]['file'] = $obj;

par

$aHierarchy[$val]['parent'] = $res[4][$clef];
$aHierarchy[$val]['file'] = $obj;

mais bon, je ne pense pas que ça change grand chose...
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Oui j'y ai pensé...puis je n'y ai plus pensé ;-)
Je vais changer, effectivement. Faut faire gaffe à ça, façon d'écrire un code. Moi, je mets des espaces partout, d'autres pas (toi, par exemple, lol : fonction(bla) et fonction (bla) ou fonction( bla ) ou fonction ( bla )...c'est chiant lol).
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Voilà, c'est fait, et apparemment, ça marche :-)
Merci encore.
Mon application commence sérieusement à prendre forme ;-)
je suis maintenant juste un peu à court d'idée pour la faire encore évoluer lol ;-)
Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
Elle fait quoi ton application ?

Enfin, je veux dire... Elle documente que les classses ou elle fait des diagrammes d'héritage et de la doc sur les fonctions ?
Est-ce qu'elle énumère aussi les implémentations des classes/fonctions ?

(Et si elle fait tout ça... je peux l'avoir ?)
Messages postés
2350
Date d'inscription
mercredi 13 octobre 2004
Statut
Membre
Dernière intervention
18 avril 2015
3
J'ai même pas eu le temps de me pencher sur le problème que c'est déja résolu...

Rahhh, chui encore malade 4 jours et y se passe un tas de trucs !!
Messages postés
1406
Date d'inscription
mercredi 17 août 2005
Statut
Membre
Dernière intervention
28 août 2007
8
Faut pas être malalade avec Internet ;)
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Ben heu sers-toi lol :
http://www.phpcs.com/codes/PHP5-CLASSE-DOCUMENTATION-CLASSES-FONCTIONS_35950.aspx

Elle documente automatiquement les classes (remonte la hiérarchie s'il y en a une, comme tu l'as compris lol), ainsi que les fichiers de fonctions.

Bref, tu uploades tes fichiers de classes, tes fichiers de fonctions.
Puis tu choisis les fichiers que tu veux documenter, et hoip c'est fait : elle crée des fichiers html pourt la doc.
Enfin, je te laisse regarder , j'ai mis dans le zip des exemples de documentation créées. C'est très facile à utiliser.

Pour le moment, elle ne fait pas de diagramme mais c'est une super idée lol!
J'ai même une idée pour ce propos...générer ça par package (pour l'instant, c'est généré par classe/fichier de fonctions), cxela permattrait de browser un package plus facilement. Et de créer un diagramme du package justement.

Et comme ça, si tu testes, tu pourras me donner des idées :-) Et des suggestions d'améliorations. C'est un projet qui me plait et sur lequel j'aime bien passer du temps (j'ai commencé y a 5-6 jours je crois, pdt mes pauses au boulot lol).