1<?php declare(strict_types=1);
2
3namespace PhpDocReader\PhpParser;
4
5use SplFileObject;
6
7/**
8 * Parses a file for "use" declarations.
9 *
10 * Class taken and adapted from doctrine/annotations to avoid pulling the whole package.
11 *
12 * Authors: Fabien Potencier <fabien@symfony.com> and Christian Kaps <christian.kaps@mohiva.com>
13 */
14class UseStatementParser
15{
16    /**
17     * @return array A list with use statements in the form (Alias => FQN).
18     */
19    public function parseUseStatements(\ReflectionClass $class): array
20    {
21        $filename = $class->getFilename();
22        if ($filename === false) {
23            return [];
24        }
25
26        $content = $this->getFileContent($filename, $class->getStartLine());
27
28        if ($content === null) {
29            return [];
30        }
31
32        $namespace = preg_quote($class->getNamespaceName(), '/');
33        $content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
34        $tokenizer = new TokenParser('<?php ' . $content);
35
36        return $tokenizer->parseUseStatements($class->getNamespaceName());
37    }
38
39    /**
40     * Gets the content of the file right up to the given line number.
41     *
42     * @param string $filename The name of the file to load.
43     * @param int $lineNumber The number of lines to read from file.
44     */
45    private function getFileContent(string $filename, int $lineNumber): string
46    {
47        if (! is_file($filename)) {
48            throw new \RuntimeException("Unable to read file $filename");
49        }
50
51        $content = '';
52        $lineCnt = 0;
53        $file = new SplFileObject($filename);
54        while (! $file->eof()) {
55            if ($lineCnt++ === $lineNumber) {
56                break;
57            }
58
59            $content .= $file->fgets();
60        }
61
62        return $content;
63    }
64}
65