Completed
Pull Request — master (#130)
by Greg
01:45
created

FullyQualifiedClassCache   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 22
c 0
b 0
f 0
lcom 1
cbo 0
dl 0
loc 104
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A qualify() 0 5 1
A cached() 0 4 2
B primeCache() 0 23 4
A primeNamespaceCache() 0 9 2
A primeUseCache() 0 8 2
A readNamespace() 0 13 3
B readUseStatements() 0 20 5
A readNextRelevantLine() 0 9 3
1
<?php
2
namespace Consolidation\AnnotatedCommand\Parser\Internal;
3
4
class FullyQualifiedClassCache
5
{
6
    protected $classCache = [];
7
    protected $namespaceCache = [];
8
9
    public function qualify($filename, $className)
10
    {
11
        $this->primeCache($filename, $className);
12
        return $this->cached($filename, $className);
13
    }
14
15
    protected function cached($filename, $className)
16
    {
17
        return isset($this->classCache[$filename][$className]) ? $this->classCache[$filename][$className] : $className;
18
    }
19
20
    protected function primeCache($filename, $className)
21
    {
22
        // If the cache has already been primed, do no further work
23
        if (isset($this->namespaceCache[$filename])) {
24
            return false;
25
        }
26
27
        $handle = fopen($filename, "r");
28
        if (!$handle) {
29
            return false;
30
        }
31
32
        $namespaceName = $this->primeNamespaceCache($filename, $handle);
33
        $this->primeUseCache($filename, $handle);
34
35
        // If there is no 'use' statement for the className, then
36
        // generate an effective classname from the namespace
37
        if (!isset($this->classCache[$filename][$className])) {
38
            $this->classCache[$filename][$className] = $namespaceName . '\\' . $className;
39
        }
40
41
        fclose($handle);
42
    }
43
44
    protected function primeNamespaceCache($filename, $handle)
45
    {
46
        $namespaceName = $this->readNamespace($handle);
47
        if (!$namespaceName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $namespaceName of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
48
            return false;
49
        }
50
        $this->namespaceCache[$filename] = $namespaceName;
51
        return $namespaceName;
52
    }
53
54
    protected function primeUseCache($filename, $handle)
55
    {
56
        $usedClasses = $this->readUseStatements($handle);
57
        if (empty($usedClasses)) {
58
            return false;
59
        }
60
        $this->classCache[$filename] = $usedClasses;
61
    }
62
63
    protected function readNamespace($handle)
64
    {
65
        $namespaceRegex = '#^\s*namespace\s+#';
66
        $line = $this->readNextRelevantLine($handle);
67
        if (!$line || !preg_match($namespaceRegex, $line)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $line of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
68
            print "nope!\n";
69
            return false;
70
        }
71
72
        $namespaceName = preg_replace($namespaceRegex, '', $line);
73
        $namespaceName = rtrim($namespaceName, ';');
74
        return $namespaceName;
75
    }
76
77
    protected function readUseStatements($handle)
78
    {
79
        $useRegex = '#^\s*use\s+#';
80
        $result = [];
81
        while (true) {
82
            $line = $this->readNextRelevantLine($handle);
83
            if (!$line || !preg_match($useRegex, $line)) {
84
                return $result;
85
            }
86
            $usedClass = preg_replace($useRegex, '', $line);
87
            $usedClass = rtrim($usedClass, ';');
88
            $unqualifiedClass = preg_replace('#.*\\\\#', '', $usedClass);
89
            // If this is an aliased class, 'use \Foo\Bar as Baz', then adjust
90
            if (strpos($usedClass, ' as ')) {
91
                $unqualifiedClass = preg_replace('#.*\sas\s+#', '', $usedClass);
92
                $usedClass = preg_replace('#\s+as\s+#', '', $usedClass);
93
            }
94
            $result[$unqualifiedClass] = $usedClass;
95
        }
96
    }
97
98
    protected function readNextRelevantLine($handle)
99
    {
100
        while (($line = fgets($handle)) !== false) {
101
            if (preg_match('#^\s*\w#', $line)) {
102
                return trim($line);
103
            }
104
        }
105
        return false;
106
    }
107
}
108