Completed
Push — master ( 81db43...f030be )
by Aleh
12s
created

Parser::parseContent()   B

Complexity

Conditions 3
Paths 6

Size

Total Lines 24
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 3
Metric Value
c 5
b 0
f 3
dl 0
loc 24
rs 8.9713
cc 3
eloc 19
nc 6
nop 3
1
<?php
2
3
namespace Padawan\Parser;
4
5
use Padawan\Domain\Project\FQN;
6
use Padawan\Domain\Project\Node\Uses;
7
use Padawan\Framework\Utils\PathResolver;
8
use PhpParser\ParserFactory;
9
use PhpParser\NodeTraverser as Traverser;
10
use Psr\Log\LoggerInterface;
11
use Padawan\Parser\NamespaceParser;
12
13
class Parser
14
{
15
16
    public function __construct(
17
        ParserFactory $parserFactory,
18
        Traverser $traverser,
19
        UseParser $useParser,
20
        NamespaceParser $namespaceParser,
21
        LoggerInterface $logger
22
    ) {
23
        $this->parserFactory    = $parserFactory;
24
        $this->traverser        = $traverser;
25
        $this->useParser        = $useParser;
26
        $this->namespaceParser  = $namespaceParser;
27
        $this->walker           = [];
28
        $this->astPool          = [];
29
        $this->logger           = $logger;
30
    }
31
    public function parseContent($file, $content, Uses $uses = null)
32
    {
33
        if (!$uses instanceof Uses) {
34
            $uses = new Uses(new FQN);
35
        }
36
        $this->setUses($uses);
37
        $this->setFileInfo($uses, $file);
38
        try {
39
            $parser = $this->parserFactory->create(ParserFactory::PREFER_PHP5);
40
            $ast = $parser->parse($content);
41
        } catch (\Exception $e) {
42
            $this->logger->error(sprintf("Parsing failed in file %s\n", $file));
43
            $this->logger->error($e);
44
            $this->clearWalkers();
45
            return;
46
        }
47
        $this->logger->addInfo(sprintf("Traversing with %s walkers",
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Log\LoggerInterface as the method addInfo() does only exist in the following implementations of said interface: Monolog\Logger.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
48
            count($this->walkers)
0 ignored issues
show
Bug introduced by
The property walkers does not seem to exist. Did you mean walker?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
49
        ));
50
        $this->traverser->traverse($ast);
51
        $nodes = $this->getResultScopes();
52
        $this->clearWalkers();
53
        return $nodes;
54
    }
55
    public function setUses(Uses $uses)
56
    {
57
        $this->uses = $uses;
58
        $this->useParser->setUses($uses);
59
        $this->namespaceParser->setUses($uses);
60
    }
61
    public function getUses()
62
    {
63
        return $this->uses;
64
    }
65
    public function parseFQCN($fqcn)
66
    {
67
        return $this->useParser->parseFQCN($fqcn);
68
    }
69
    public function addWalker($walker)
70
    {
71
        $this->walkers[] = $walker;
0 ignored issues
show
Bug introduced by
The property walkers does not seem to exist. Did you mean walker?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
72
        $this->traverser->addVisitor($walker);
73
    }
74
    public function clearWalkers() {
75
        foreach ($this->walkers AS $walker) {
0 ignored issues
show
Bug introduced by
The property walkers does not seem to exist. Did you mean walker?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
76
            $this->traverser->removeVisitor($walker);
77
        }
78
        $this->walkers = [];
0 ignored issues
show
Bug introduced by
The property walkers does not seem to exist. Did you mean walker?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
79
    }
80
    public function getResultScopes()
81
    {
82
        $nodes = [];
83
        foreach ($this->walkers as $walker) {
0 ignored issues
show
Bug introduced by
The property walkers does not seem to exist. Did you mean walker?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
84
            $nodes[] = $walker->getResultScope();
85
        }
86
        if (count($nodes) === 1) {
87
            return array_pop($nodes);
88
        }
89
        return $nodes;
90
    }
91
    public function setIndex($index)
92
    {
93
        foreach ($this->walkers as $walker) {
0 ignored issues
show
Bug introduced by
The property walkers does not seem to exist. Did you mean walker?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
94
            $walker->setIndex($index);
95
        }
96
    }
97
98
    protected function setFileInfo(Uses $uses, $file)
99
    {
100
        foreach ($this->walkers as $walker) {
0 ignored issues
show
Bug introduced by
The property walkers does not seem to exist. Did you mean walker?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
101
            $walker->updateFileInfo($uses, $file);
102
        }
103
    }
104
105
    private $parsedClasses = [];
0 ignored issues
show
Unused Code introduced by
The property $parsedClasses is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
106
    /** @var ParserFactory */
107
    private $parserFactory;
108
    /** @var Traverser */
109
    private $traverser;
110
    /** @var Walker\WalkerInterface[] */
111
    private $walker;
112
    private $astPool;
113
    private $logger;
114
    /** @var NamespaceParser */
115
    private $namespaceParser;
116
    private $useParser;
117
    private $uses;
118
}
119