POZOR! Článek jsem napsal před více jak rokem, a tudíž už nemusí reflektovat můj nynější názor nebo může být zastaralý.
Řešil jsem před nedávnem (při vytváření videa o cyklomatické komplexitě), jak nejlépe PHP funkci zobrazit ve formě grafu (respektive CFG – content flow graph).
Ideální nástroj, kde bych vložit PHP kód a získal ihned graf, jsem bohužel nenašel. Popíši tedy postup, který mi přišel jako ideální bez toho, abych si psal vlastní knihovnu.
Narazil jsem na ircmaxell/php-cfg, které je takovým mezikrokem za cestou k vytouženému grafu. Schroustá PHP kód a vyplivne kód ve formátu pro GraphViz.
Pokud mám tento PHP kód:
<?php
function index($a, $b) {
$value = 1;
for ($i=$a;$i<$b;$i++) {
$value++;
}
return $value;
}
Proženu jej knihovnou PHP-CFG pomocí skriptu:
<?php
include "vendor/autoload.php";
$parser = new PHPCfg\Parser(
(new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7)
);
$file = "index.php";
$script = $parser->parse(file_get_contents($file), $file);
$dumper = new PHPCfg\Printer\GraphViz();
echo $dumper->printFunc($script->functions[0]);
A získám DOT kód:
digraph "cfg" {
"block_1" -> "block_2" [
label="target"
]
"block_2" -> "block_3" [
label="if"
]
"block_2" -> "block_4" [
label="else"
]
"block_3" -> "block_5" [
label="target"
]
"block_4" -> "block_6" [
label="target"
]
"block_5" -> "block_2" [
label="target"
]
"block_1" [
label="\l Expr_Param\l name: LITERAL(\'a\')\l result: Var#1<$a>\l Expr_Param\l name: LITERAL(\'b\')\l result: Var#2<$b>\l Expr_Assign\l var: Var#3<$value>\l expr: LITERAL(1)\l result: Var#4\l Expr_Assign\l var: Var#5<$i>\l expr: Var#1<$a>\l result: Var#6\l Stmt_Jump"
shape="rect"
]
"block_2" [
label="\l Var#7<$i> = Phi(Var#5<$i>, Var#8<$i>)\l Var#9<$b> = Phi(Var#2<$b>)\l Var#10<$value> = Phi(Var#3<$value>, Var#11<$value>)\l Expr_BinaryOp_Smaller\l left: Var#7<$i>\l right: Var#9<$b>\l result: Var#12\l Stmt_JumpIf\l cond: Var#12"
shape="rect"
]
"block_3" [
label="\l Var#13<$value> = Phi(Var#10<$value>)\l Expr_BinaryOp_Plus\l left: Var#13<$value>\l right: LITERAL(1)\l result: Var#14\l Expr_Assign\l var: Var#11<$value>\l expr: Var#14\l result: Var#15\l Stmt_Jump"
shape="rect"
]
"block_4" [
label="\l Stmt_Jump"
shape="rect"
]
"block_5" [
label="\l Var#16<$i> = Phi(Var#7<$i>)\l Expr_BinaryOp_Plus\l left: Var#16<$i>\l right: LITERAL(1)\l result: Var#17\l Expr_Assign\l var: Var#8<$i>\l expr: Var#17\l result: Var#18\l Stmt_Jump"
shape="rect"
]
"block_6" [
label="\l Var#19<$value> = Phi(Var#10<$value>)\l Terminal_Return\l expr: Var#19<$value>"
shape="rect"
]
}
Na tento kód jsem si stáhl GraphViz - www.graphviz.org. Díky tomu je přes příkazovou řádku dostupný příkaz "dot" a vygenerujete si například PNG.
dot file.dot -Tpng -o image.png
A konečně ve výsledku dostanete graf :)
Znáte někoho, komu by článek mohl pomoct? Zasdílejte mu ho :)