FileHelper_PHPClassInfo::stripWhitespace()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1
c 2
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * File containing the {@link FileHelper_PHPClassInfo} class.
4
 * 
5
 * @package Application Utils
6
 * @subpackage FileHelper
7
 * @see FileHelper_PHPClassInfo
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils;
13
14
use AppUtils\FileHelper\PHPFile;
15
16
/**
17
 * Used to retrieve information on the PHP classes contained
18
 * within the target PHP file. Does not use the reflection API.
19
 * This is meant as a quick way to check for the presence of
20
 * classes, and which classes they extend or interfaces are 
21
 * implemented.
22
 * 
23
 * @package Application Utils
24
 * @subpackage FileHelper
25
 * @author Sebastian Mordziol <[email protected]>
26
 * @see FileHelper::findPHPClasses()
27
 */
28
class FileHelper_PHPClassInfo
29
{
30
    public const TYPE_CLASS = 'class';
31
    public const TYPE_TRAIT = 'trait';
32
    public const TYPE_INTERFACE = 'interface';
33
34
    protected PHPFile $file;
35
    protected string $namespace = '';
36
37
    /**
38
     * @var array<string,FileHelper_PHPClassInfo_Class>
39
     */
40
    protected array $classes = array();
41
42
    /**
43
     * @var string[]
44
     */
45
    private static array $types = array(
46
        self::TYPE_CLASS,
47
        self::TYPE_INTERFACE,
48
        self::TYPE_TRAIT
49
    );
50
51
   /**
52
    * @param PHPFile $path The path to the PHP file to parse.
53
    * @throws FileHelper_Exception
54
    * @see FileHelper::findPHPClasses()
55
    */
56
    public function __construct(PHPFile $path)
57
    {
58
        $this->file = $path
59
            ->requireExists()
60
            ->requireReadable();
61
        
62
        $this->parseFile();
63
    }
64
    
65
   /**
66
    * The name of the namespace of the classes in the file, if any.
67
    * @return string
68
    */
69
    public function getNamespace() : string
70
    {
71
        return $this->namespace;
72
    }
73
    
74
   /**
75
    * Whether the file contains a namespace.
76
    * @return bool
77
    */
78
    public function hasNamespace() : bool
79
    {
80
        return !empty($this->namespace);
81
    }
82
    
83
   /**
84
    * The absolute path to the file.
85
    * @return string
86
    */
87
    public function getPath() : string
88
    {
89
        return $this->file->getPath();
90
    }
91
   
92
   /**
93
    * Whether any classes were found in the file.
94
    * @return bool
95
    */
96
    public function hasClasses() : bool
97
    {
98
        return !empty($this->classes);
99
    }
100
    
101
   /**
102
    * The names of the classes that were found in the file (with namespace if any).
103
    * @return string[]
104
    */
105
    public function getClassNames() : array
106
    {
107
        return array_keys($this->classes);
108
    }
109
    
110
   /**
111
    * Retrieves all classes that were detected in the file,
112
    * which can be used to retrieve more information about
113
    * them.
114
    * 
115
    * @return FileHelper_PHPClassInfo_Class[]
116
    */
117
    public function getClasses() : array
118
    {
119
        return array_values($this->classes);
120
    }
121
122
    protected function parseFile() : void
123
    {
124
        $code = php_strip_whitespace($this->getPath());
125
126
        $this->detectNamespace($code);
127
        $result = $this->detectMatches($code);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->detectMatches($code) targeting AppUtils\FileHelper_PHPClassInfo::detectMatches() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
128
129
        if($result === null) {
0 ignored issues
show
introduced by
The condition $result === null is always true.
Loading history...
130
            return;
131
        }
132
        
133
        $indexes = array_keys($result[0]);
134
        
135
        foreach($indexes as $idx)
136
        {
137
            $this->parseResult(
138
                $result[1][$idx],
139
                $result[3][$idx],
140
                $result[2][$idx],
141
                $result[4][$idx],
142
                $result[5][$idx]
143
            );
144
        }
145
    }
146
147
    /**
148
     * @param string $code
149
     * @return array<int,array<int,string>>|null
150
     */
151
    private function detectMatches(string $code) : ?array
152
    {
153
        $types = implode('|', self::$types);
154
        $result = array();
155
156
        preg_match_all('/(abstract|final)\s+('.$types.')\s+([\sa-z\d\\\\_,]+){|('.$types.')\s+([\sa-z\d\\\\_,]+){/ix', $code, $result, PREG_PATTERN_ORDER);
157
158
        if(isset($result[0][0])) {
159
            return $result;
160
        }
161
162
        return null;
163
    }
164
165
    private function detectNamespace(string $code) : void
166
    {
167
        $result = array();
168
        preg_match_all('/namespace\s+([^;]+);/ix', $code, $result, PREG_PATTERN_ORDER);
169
170
        if(isset($result[0][0])) {
171
            $this->namespace = trim($result[1][0]);
172
        }
173
    }
174
175
    private function parseResult(string $keyword, string $declaration, string $type, string $simpleType, string $simpleDeclaration) : void
176
    {
177
        if(empty($keyword)) {
178
            $type = $simpleType;
179
            $declaration = $simpleDeclaration;
180
        }
181
182
        $class = new FileHelper_PHPClassInfo_Class(
183
            $this,
184
            $this->stripWhitespace($declaration),
185
            trim($keyword),
186
            $type
187
        );
188
189
        $this->classes[$class->getNameNS()] = $class;
190
    }
191
192
   /**
193
    * Strips all whitespace from the string, replacing it with 
194
    * regular spaces (newlines, tabs, etc.).
195
    * 
196
    * @param string $string
197
    * @return string
198
    */
199
    protected function stripWhitespace(string $string) : string 
200
    {
201
        return preg_replace('/\s/', ' ', $string);
202
    }
203
}
204