Completed
Push — master ( c4e3cd...c5cae6 )
by Anton
05:38
created

Tokenizer   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 164
Duplicated Lines 25.61 %

Coupling/Cohesion

Components 2
Dependencies 11

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 15
c 7
b 0
f 0
lcom 2
cbo 11
dl 42
loc 164
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A fetchTokens() 0 4 1
A fileReflection() 0 17 3
A classLocator() 21 21 4
A invocationLocator() 21 21 4
A createInjection() 0 8 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\Tokenizer;
9
10
use Spiral\Core\Component;
11
use Spiral\Core\Container\InjectorInterface;
12
use Spiral\Core\Container\SingletonInterface;
13
use Spiral\Core\HippocampusInterface;
14
use Spiral\Debug\Traits\BenchmarkTrait;
15
use Spiral\Debug\Traits\LoggerTrait;
16
use Spiral\Files\FilesInterface;
17
use Spiral\Tokenizer\Configs\TokenizerConfig;
18
use Spiral\Tokenizer\Reflections\ReflectionFile;
19
use Spiral\Tokenizer\Traits\TokensTrait;
20
use Symfony\Component\Finder\Finder;
21
22
/**
23
 * Default implementation of spiral tokenizer support while and blacklisted directories and etc.
24
 */
25
class Tokenizer extends Component implements SingletonInterface, TokenizerInterface, InjectorInterface
26
{
27
    /**
28
     * Required traits.
29
     */
30
    use LoggerTrait, BenchmarkTrait, TokensTrait;
31
32
    /**
33
     * Declares to IoC that component instance should be treated as singleton.
34
     */
35
    const SINGLETON = self::class;
36
37
    /**
38
     * Memory section.
39
     */
40
    const MEMORY = 'tokenizer';
41
42
    /**
43
     * Cache of already processed file reflections, used to speed up lookup.
44
     *
45
     * @invisible
46
     * @var array
47
     */
48
    private $cache = [];
49
50
    /**
51
     * @var TokenizerConfig
52
     */
53
    protected $config = null;
54
55
    /**
56
     * @invisible
57
     * @var FilesInterface
58
     */
59
    protected $files = null;
60
61
    /**
62
     * @invisible
63
     * @var HippocampusInterface
64
     */
65
    protected $memory = null;
66
67
    /**
68
     * Tokenizer constructor.
69
     *
70
     * @param FilesInterface       $files
71
     * @param TokenizerConfig      $config
72
     * @param HippocampusInterface $runtime
73
     */
74
    public function __construct(
75
        FilesInterface $files,
76
        TokenizerConfig $config,
77
        HippocampusInterface $runtime
78
    ) {
79
        $this->files = $files;
80
        $this->config = $config;
81
        $this->memory = $runtime;
82
83
        $this->cache = $this->memory->loadData(static::MEMORY);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->memory->loadData(static::MEMORY) can also be of type string or null. However, the property $cache is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     *
89
     * @deprecated this method creates looped dependencies, drop it
90
     */
91
    public function fetchTokens($filename)
92
    {
93
        return $this->normalizeTokens(token_get_all($this->files->read($filename)));
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    public function fileReflection($filename)
100
    {
101
        $fileMD5 = $this->files->md5($filename = $this->files->normalizePath($filename));
102
103
        if (isset($this->cache[$filename]) && $this->cache[$filename]['md5'] == $fileMD5) {
104
            //We can speed up reflection via tokenization cache
105
            return new ReflectionFile($filename, $this, $this->cache[$filename]);
106
        }
107
108
        $reflection = new ReflectionFile($filename, $this);
109
110
        //Let's save to cache
111
        $this->cache[$filename] = ['md5' => $fileMD5] + $reflection->exportSchema();
112
        $this->memory->saveData(static::MEMORY, $this->cache);
113
114
        return $reflection;
115
    }
116
117
    /**
118
     * Get pre-configured class locator.
119
     *
120
     * @param array  $directories
121
     * @param array  $exclude
122
     * @param Finder $finder
123
     * @return ClassLocator
124
     */
125 View Code Duplication
    public function classLocator(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
126
        array $directories = [],
127
        array $exclude = [],
128
        Finder $finder = null
129
    ) {
130
        $finder = !empty($finder) ?: new Finder();
131
132
        if (empty($directories)) {
133
            $directories = $this->config->getDirectories();
134
        }
135
136
        if (empty($exclude)) {
137
            $exclude = $this->config->getExcludes();
138
        }
139
140
        //Configuring finder
141
        return new ClassLocator(
142
            $this,
143
            $finder->files()->in($directories)->exclude($exclude)->name('*.php')
144
        );
145
    }
146
147
    /**
148
     * Get pre-configured invocation locator.
149
     *
150
     * @param array  $directories
151
     * @param array  $exclude
152
     * @param Finder $finder
153
     * @return ClassLocator
154
     */
155 View Code Duplication
    public function invocationLocator(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
        array $directories = [],
157
        array $exclude = [],
158
        Finder $finder = null
159
    ) {
160
        $finder = !empty($finder) ?: new Finder();
161
162
        if (empty($directories)) {
163
            $directories = $this->config->getDirectories();
164
        }
165
166
        if (empty($exclude)) {
167
            $exclude = $this->config->getExcludes();
168
        }
169
170
        //Configuring finder
171
        return new InvocationLocator(
172
            $this,
173
            $finder->files()->in($directories)->exclude($exclude)->name('*.php')
174
        );
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180
    public function createInjection(\ReflectionClass $class, $context = null)
181
    {
182
        if ($class->isSubclassOf(ClassLocatorInterface::class)) {
183
            return $this->classLocator();
184
        } else {
185
            return $this->invocationLocator();
186
        }
187
    }
188
}