Skip to content

Instantly share code, notes, and snippets.

@drupol
Last active May 10, 2021 13:34
Show Gist options
  • Save drupol/11a0e396722a80a72e674d2cb6f22659 to your computer and use it in GitHub Desktop.
Save drupol/11a0e396722a80a72e674d2cb6f22659 to your computer and use it in GitHub Desktop.
Simple example of nikic/php-parser importer in loophp/phptree
<?php
declare(strict_types=1);
include __DIR__ . '/vendor/autoload.php';
use drupol\launcher\Launcher;
use loophp\phptree\Exporter\Image;
use PhpParser\ParserFactory;
use loophp\phptree\Importer\NikicPhpParserImporter;
$code = file_get_contents(__DIR__ . '/src/Cart.php');
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
$tree = (new NikicPhpParserImporter())->import($parser->parse($code));
$exporter = new Image();
$imagePath = $exporter->setFormat('png')->export($tree);
Launcher::open($imagePath);
@drupol
Copy link
Author

drupol commented May 10, 2021

Hello !

Something like this?

<?php

declare(strict_types=1);

include __DIR__ . '/vendor/autoload.php';

use loophp\launcher\Launcher;
use loophp\phptree\Exporter\Image;
use loophp\phptree\Importer\ImporterInterface;
use PhpParser\ParserFactory;
use loophp\phptree\Node\AttributeNode;
use loophp\phptree\Node\AttributeNodeInterface;
use PhpParser\Node;
use loophp\phptree\Node\NodeInterface;

final class NikicPhpParserWithLineNumbers implements ImporterInterface {
    /**
     * @param Node[] $data
     *
     * @throws Exception
     */
    public function import($data): NodeInterface
    {
        return $this->parseNode($this->createNode(['label' => 'root']), ...$data);
    }

    private function createNode(array $attributes): AttributeNodeInterface
    {
        if (array_key_exists('astNode', $attributes)) {
            $attributes['label'] = sprintf(
                '%s at line %s',
                $attributes['astNode']->getType(),
                $attributes['astNode']->getLine()
            );
        }

        return new AttributeNode($attributes);
    }

    /**
     * @return array<int, Node>
     */
    private function getAllNodeChildren(Node $astNode): array
    {
        /** @var array<int, array<int, Node>> $astNodes */
        $astNodes = array_map(
            static function (string $subNodeName) use ($astNode): array {
                $subNodes = $astNode->{$subNodeName};

                if (!is_array($subNodes)) {
                    $subNodes = [$subNodes];
                }

                return array_filter(
                    $subNodes,
                    'is_object'
                );
            },
            $astNode->getSubNodeNames()
        );

        return array_merge(...$astNodes);
    }

    /**
     * @param Node ...$astNodes
     */
    private function parseNode(AttributeNodeInterface $parent, Node ...$astNodes): NodeInterface
    {
        return array_reduce(
            $astNodes,
            function (AttributeNodeInterface $carry, Node $astNode): NodeInterface {
                return $carry
                    ->add(
                        $this->parseNode(
                            $this->createNode([
                                'label' => $astNode->getType(),
                                'astNode' => $astNode,
                            ]),
                            ...$this->getAllNodeChildren($astNode)
                        )
                    );
            },
            $parent
        );
    }
}

$code = file_get_contents(__DIR__ . '/src/Exporter/FancyExporter.php');

$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);

$tree = (new NikicPhpParserWithLineNumbers())->import($parser->parse($code));

$exporter = new Image();
$filename = tempnam(sys_get_temp_dir(), 'graph-');

file_put_contents($filename, $exporter->setFormat('svg')->export($tree));

Launcher::open($filename);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment