Introduction
Le package PECL inclued est une extension PHP permettant d’affecter son comportement. Cette extension permet d’afficher des informations sur les différents fichiers inclus par les instructions de langage include(), include_once(), require() et require_once().
En plus de renvoyer des informations bien complètes sur l’arbre d’inclusion des fichiers, nous verrons un peu plus bas comment générer des graphes à partir de cette extension couplée à Graphviz.
Inclued peut être utile lors d’une phase de débug, lorsque vous jouez un peu avec les inclusions si celles-ci sont nombreuses. Les inclusions automatiques via la fonction __autoload() peuvent parfois être contraignantes lors d’une utilisation massive de classes.

Installation
Inclued vient à peine de sortir en version bêta peut s’installer via PECL. Pour cela, lancez votre Terminal, et installez inclued en forçant la main :
/htdocs/lab% sudo pecl install -f inclued WARNING: failed to download pecl.php.net/inclued within preferred state "stable", will instead download version 0.1.1, stability "beta" downloading inclued-0.1.1.tgz ... Starting to download inclued-0.1.1.tgz (9,022 bytes) .....done: 9,022 bytes 5 source files, building running: phpize Configuring for: PHP Api Version: 20090626 Zend Module Api No: 20090626 Zend Extension Api No: 220090626 # ... Build process completed successfully Installing '/opt/local/lib/php/extensions/no-debug-non-zts-20090626/inclued.so' install ok: channel://pecl.php.net/inclued-0.1.1 configuration option "php_ini" is not set to php.ini location You should add "extension=inclued.so" to php.ini /htdocs/lab%
N’oubliez pas de rajouter la directive inclued.enabled = 1; dans votre php.ini sinon l’extension sera chargée mais pas activée.
D’ailleurs pour cela :
1 2 3 4 5 6 | <?php // Test du package inclued echo '<h1>PHP: inclued extension test</h1><p>Current PHP version: ' . phpversion() . '<br />Inclued extension loaded: '; echo function_exists('inclued_get_data') ? 'true' : 'false'; echo '<br />Inclued extension enabled: '; echo ini_get('inclued.enabled') ? 'true</p>' : 'false</p>'; |
PHP: inclued extension test Current PHP version: 5.3.1 Inclued extension loaded: true Inclued extension enabled: true
Test
Placez-vous dans un répertoire avec quelques fichiers et classes et faites des inclusions de fichiers :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php include 'lab.php'; // includes a « require 'path.func.php' » include 'listFiles.class.php'; require_once 'test_class.php'; include_once 'listFiles.class.php'; $clue = inclued_get_data(); // On affiche les données recueillies echo '<pre>'; print_r($clue); echo '<//pre>'; // On sauve les données dans un fichier (pour la suite) if (fopen('inclued.data', 'w+')) { if (is_writable('inclued.data')) { file_put_contents('inclued.data', serialize($clue)); } } |
De cette manière-ci, vous obtenez un tableau multi-dimensionnel contenant un tas d’informations dans même genre que celui-ci :
Array
(
[request] => Array
(
[_COOKIE] => Array
(
)
[SCRIPT_FILENAME] => /htdocs/lab/inclued.php
[REQUEST_URI] => /lab/inclued.php
[REQUEST_TIME] => 1267217047
)
[includes] => Array
(
[0] => Array
(
[operation] => include
[op_type] => 2
[filename] => lab.php
[opened_path] => /htdocs/lab/lab.php
[fromfile] => /htdocs/lab/inclued.php
[fromline] => 9
)
[1] => Array
(
[operation] => require
[op_type] => 8
[filename] => path.func.php
[opened_path] => /htdocs/lab/path.func.php
[fromfile] => /htdocs/lab/lab.php
[fromline] => 46
)
[2] => Array
(
[operation] => include
[op_type] => 2
[filename] => listFiles.class.php
[opened_path] => /htdocs/lab/listFiles.class.php
[fromfile] => /htdocs/lab/inclued.php
[fromline] => 10
)
[3] => Array
(
[operation] => require_once
[op_type] => 16
[filename] => test_class.php
[opened_path] => /htdocs/lab/test_class.php
[fromfile] => /htdocs/lab/inclued.php
[fromline] => 11
)
[4] => Array
(
[operation] => include_once
[op_type] => 4
[filename] => listFiles.class.php
[opened_path] => /htdocs/lab/listFiles.class.php
[duplicate] => 1
[fromfile] => /htdocs/lab/inclued.php
[fromline] => 12
)
)
[inheritance] => Array
(
)
[classes] => Array
(
[0] => Array
(
[name] => listFiles
[filename] => /htdocs/lab/listFiles.class.php
[line] => 26
)
[1] => Array
(
[name] => Foo
[mangled_name] => foo
[filename] => /htdocs/lab/test_class.php
[line] => 2
)
[2] => Array
(
[name] => Bar
[mangled_name] => bar
[filename] => /htdocs/lab/test_class.php
[line] => 14
[parent] => Array
(
[name] => Foo
[filename] => /htdocs/lab/test_class.php
[line] => 2
)
)
)
)On notera la présence de l’entrée [duplicate] => 1 lors de l’include_once de la classe listFiles.class.php. Vraiment pratique et précis.
Vous avez maintenant l’arbre d’inclusion de vos fichiers décrit de façon assez précis mais pas très bien exploitable encore. Il serait beaucoup plus ludique et accessible d’obtenir une présentation plus tape à l’oeil, un peu comme des graphes
.
Générer un graphe avec Graphviz
Installez Graphviz avec votre gestionnaire de paquets préféré mais attention, il y a une forte dépendance de paquets alors ne faite pas cela quand vous êtes pressé…
/htdocs/lab% sudo port install graphviz
Graphiz travaille avec des fichiers .DOT donc il vous faudra convertir votre tableau multi-dimensionnel en ce genre de fichier. Heureusement, l’un des deux développeurs de inclued a pensé à cela et donc vous devriez trouver le fichier gengraph.php dans votre include_path :
/htdocs/lab% php -r 'echo get_include_path();' .:/opt/local/lib/php% /htdocs/lab% php /opt/local/lib/php/gengraph.php /opt/local/lib/php/gengraph.php -i <inclued_dump> [-t includes|classes] [-o <output_file>] [-d docroot] zsh: exit 1 php /opt/local/lib/php/gengraph.php /htdocs/lab%
On va donc transformer notre fichier inclued.data en inclued.dot et générer inclued.png :
/htdocs/lab% php -f /opt/local/lib/php/gengraph.php -- -i inclued.data -o inclued.dot Written inclued.dot... To generate images: dot -Tpng -o inclued.png inclued.dot /htdocs/lab% dot -Tpng -o inclued.png inclued.dot /htdocs/lab%
Théoriquement vous devriez avoir un graphe de ce genre :

Personnellement, je ne trouve pas cela terrible et j’aime bien qu’un arbre soit descendant. Puis dans mon exemple, je n’ai que faire des chemins absolus.
Editons le fichier gengraph.php :
57 58 59 60 | <?php // On rajoute quelques basename() et le tour est joué $short_fromfile = basename(str_replace($docroot, '', $inc['fromfile'])); $short_opened_path = basename(str_replace($docroot, '', $inc['opened_path'])); |
63 64 65 | <?php // On rajoute aussi un basename() ici $short_fromfile = basename(str_replace($docroot, '', $autoload['fromfile'])); |
159 160 161 162 163 164 165 166 | <?php // On supprime la restriction de taille (la clause "size") $content = <<<EOF digraph phpdeps { node [shape = ellipse]; node [color="#add960", style=filled]; graph [bgcolor="#ffffff"]; EOF; |
171 172 173 174 175 176 177 | <?php /* On supprime la clause qui permet au graphe de s'étendre horizontalement plutôt que verticalement (par défaut) $content = <<<EOF rankdir = "LR"; EOF; fwrite($fp, $content); */ |
Ainsi ces modifications faites, relancez vos commandes et vous devriez avoir un magnifique résultat :

Rien à voir, cela fait vraiment pro’. On remarquera toujours le duplicate avec sa flèche en pointillés.
Les possibilités d’enrichissement graphiques sont très grandes car Graphviz offre réellement une configuration poussée et la possibilité de générer des graphiques très avancés. Voie à explorer…
Vous savez désormais comment générer de manière très lisible un graphe d’arbre d’inclusion avec PHP et pour PHP. D’ailleurs, j’en ai profité pour lancer un petit projet avec une classe Inclued
.


Voilà quelque chose d’utile pour analyser globalement un projet, merci pour cet article concret et pratique.
D’autant que l’écriture des données peut être mise dans le append_auto_file avec un test sur le fait que le module est ou non activé, ce qui permet de rendre les choses systématiques.
Je vais tester ça.
Cédric