public
Description: A combined runtime/static code-analysis tool, that can trace parameter types
Homepage:
Clone URL: git://github.com/troelskn/php-tracer-weaver.git
php-tracer-weaver / reflector.inc.php
100644 111 lines (108 sloc) 3.674 kb
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];
  }
}