forked from troelskn/phpweaver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreflector.inc.php
111 lines (108 loc) · 3.59 KB
/
reflector.inc.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?php
interface ClassCollator {
function collate($first, $second);
}
class DummyClassCollator implements ClassCollator {
function collate($first, $second) {
return 'mixed';
}
}
class TraceIncludesLogger {
protected $reflector;
protected $includes = array();
function __construct(StaticReflector $reflector) {
$this->reflector = $reflector;
}
function log($trace) {
$filename = isset($trace['filename']) ? $trace['filename'] : '';
if (!isset($this->includes[$filename]) && is_file($filename)) {
$this->reflector->scanFile($filename);
}
$this->includes[$filename] = true;
}
function log_include($trace) {
$this->log($trace);
}
}
class StaticReflector implements ClassCollator {
protected $scanner;
protected $names = array();
protected $typemap = array();
protected $collate_cache = array();
protected $ancestors_cache = array();
function __construct() {
$this->scanner = new ScannerMultiplexer();
$class_scanner = $this->scanner->appendScanner(new ClassScanner());
$inheritance_scanner = $this->scanner->appendScanner(new ClassExtendsScanner($class_scanner));
$inheritance_scanner->notifyOnExtends(array($this, 'logSupertype'));
$inheritance_scanner->notifyOnImplements(array($this, 'logSupertype'));
}
function logSupertype($class, $super) {
$this->names[strtolower($super)] = $super;
$this->names[strtolower($class)] = $class;
$class = strtolower($class);
$super = strtolower($super);
if (!isset($this->typemap[$class])) {
$this->typemap[$class] = array();
}
if (!in_array($super, $this->typemap[$class])) {
$this->typemap[$class][] = $super;
}
}
function scanFile($file) {
$this->scanString(file_get_contents($file));
}
function scanString($php_source) {
$this->collate_cache = array();
$this->ancestors_cache = array();
$tokenizer = new TokenStreamParser();
$token_stream = $tokenizer->scan($php_source);
$token_stream->iterate($this->scanner);
}
function export() {
return $this->typemap;
}
protected function symbolsToNames($symbols = array()) {
$names = array();
foreach ($symbols as $symbol) {
$names[] = $this->names[$symbol];
}
return $names;
}
function ancestors($class) {
$class = strtolower($class);
return $this->symbolsToNames(isset($this->typemap[$class]) ? $this->typemap[$class] : array());
}
function ancestorsAndSelf($class) {
$class = strtolower($class);
return $this->symbolsToNames(isset($this->typemap[$class]) ? array_merge(array($class), $this->typemap[$class]) : array($class));
}
function allAncestors($class) {
$class = strtolower($class);
if (isset($this->ancestors_cache[$class])) {
return $this->ancestors_cache[$class];
}
$result = $this->ancestors($class);
foreach ($result as $p) {
$result = array_merge($result, $this->allAncestors($p));
}
$this->ancestors_cache[$class] = $result;
return $result;
}
function allAncestorsAndSelf($class) {
return array_merge(array($this->names[strtolower($class)]), $this->allAncestors($class));
}
/**
* Finds the first common ancestor, if possible
*/
function collate($first, $second) {
$first = strtolower($first);
$second = strtolower($second);
$id = "$first:$second";
if (!array_key_exists($id, $this->collate_cache)) {
$intersection = array_intersect($this->allAncestorsAndSelf($first), $this->allAncestorsAndSelf($second));
$this->collate_cache[$id] = count($intersection) > 0 ? array_shift($intersection) : '*CANT_COLLATE*';
}
return $this->collate_cache[$id];
}
}