ClosureAnalyzer.php
1.77 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
<?php namespace SuperClosure\Analyzer;
use SuperClosure\Exception\ClosureAnalysisException;
abstract class ClosureAnalyzer
{
/**
* Analyzer a given closure.
*
* @param \Closure $closure
*
* @throws ClosureAnalysisException
*
* @return array
*/
public function analyze(\Closure $closure)
{
$data = [
'reflection' => new \ReflectionFunction($closure),
'code' => null,
'hasThis' => false,
'context' => [],
'hasRefs' => false,
'binding' => null,
'scope' => null,
'isStatic' => $this->isClosureStatic($closure),
];
$this->determineCode($data);
$this->determineContext($data);
$this->determineBinding($data);
return $data;
}
abstract protected function determineCode(array &$data);
/**
* Returns the variables that are in the "use" clause of the closure.
*
* These variables are referred to as the "used variables", "static
* variables", "closed upon variables", or "context" of the closure.
*
* @param array $data
*/
abstract protected function determineContext(array &$data);
private function determineBinding(array &$data)
{
$data['binding'] = $data['reflection']->getClosureThis();
if ($scope = $data['reflection']->getClosureScopeClass()) {
$data['scope'] = $scope->getName();
}
}
private function isClosureStatic(\Closure $closure)
{
$closure = @$closure->bindTo(new \stdClass);
if ($closure === null) {
return true;
}
$rebound = new \ReflectionFunction($closure);
return $rebound->getClosureThis() === null;
}
}