1 | <?php |
||
19 | final class CodeGen implements CodeGenInterface |
||
20 | { |
||
21 | /** |
||
22 | * @var \PhpParser\Parser |
||
23 | */ |
||
24 | private $parser; |
||
25 | |||
26 | /** |
||
27 | * @var \PhpParser\BuilderFactory |
||
28 | */ |
||
29 | private $factory; |
||
30 | |||
31 | /** |
||
32 | * @var \PhpParser\PrettyPrinter\Standard |
||
33 | */ |
||
34 | private $printer; |
||
35 | |||
36 | /** |
||
37 | * @var CodeGenMethod |
||
38 | */ |
||
39 | private $codeGenMethod; |
||
40 | |||
41 | /** |
||
42 | * @var IndexedReader |
||
43 | */ |
||
44 | private $reader; |
||
45 | |||
46 | /** |
||
47 | * @param \PhpParser\Parser $parser |
||
48 | * @param \PhpParser\BuilderFactory $factory |
||
49 | * @param \PhpParser\PrettyPrinter\Standard $printer |
||
50 | */ |
||
51 | 26 | public function __construct( |
|
52 | Parser $parser, |
||
53 | BuilderFactory $factory, |
||
54 | Standard $printer |
||
55 | ) { |
||
56 | 26 | $this->parser = $parser; |
|
57 | 26 | $this->factory = $factory; |
|
58 | 26 | $this->printer = $printer; |
|
59 | 26 | $this->codeGenMethod = new CodeGenMethod($parser, $factory, $printer); |
|
60 | 26 | $this->reader = new IndexedReader(new AnnotationReader); |
|
61 | 26 | } |
|
62 | |||
63 | /** |
||
64 | * @param string $class |
||
65 | * @param \ReflectionClass $sourceClass |
||
66 | * @param BindInterface $bind |
||
67 | * |
||
68 | * @return string |
||
69 | */ |
||
70 | 11 | public function generate($class, \ReflectionClass $sourceClass, BindInterface $bind) |
|
71 | { |
||
72 | 11 | $methods = $this->codeGenMethod->getMethods($sourceClass, $bind); |
|
73 | $stmt = $this |
||
74 | 11 | ->getClass($class, $sourceClass) |
|
75 | 11 | ->addStmts($methods) |
|
76 | 11 | ->getNode(); |
|
77 | 11 | $stmt = $this->addClassDocComment($stmt, $sourceClass); |
|
78 | 11 | $code = $this->printer->prettyPrint([$stmt]); |
|
79 | 11 | $statements = $this->getUseStatements($sourceClass); |
|
80 | |||
81 | 11 | return $statements . $code; |
|
82 | } |
||
83 | |||
84 | /** |
||
85 | * @param \ReflectionClass $class |
||
86 | * |
||
87 | * @return string |
||
88 | */ |
||
89 | 11 | private function getUseStatements(\ReflectionClass $class) |
|
90 | { |
||
91 | 11 | $traverser = new NodeTraverser(); |
|
92 | 11 | $useStmtsVisitor = new CodeGenVisitor(); |
|
93 | 11 | $traverser->addVisitor($useStmtsVisitor); |
|
94 | // parse |
||
95 | 11 | $stmts = $this->parser->parse(file_get_contents($class->getFileName())); |
|
96 | // traverse |
||
97 | 11 | $traverser->traverse($stmts); |
|
|
|||
98 | // pretty print |
||
99 | 11 | $code = $this->printer->prettyPrint($useStmtsVisitor()); |
|
100 | |||
101 | 11 | return (string) $code; |
|
102 | } |
||
103 | |||
104 | /** |
||
105 | * Return class statement |
||
106 | * |
||
107 | * @param string $newClassName |
||
108 | * @param \ReflectionClass $class |
||
109 | * |
||
110 | * @return \PhpParser\Builder\Class_ |
||
111 | */ |
||
112 | 11 | private function getClass($newClassName, \ReflectionClass $class) |
|
113 | { |
||
114 | 11 | $parentClass = $class->name; |
|
115 | 11 | $builder = $this->factory |
|
116 | 11 | ->class($newClassName) |
|
117 | 11 | ->extend($parentClass) |
|
118 | 11 | ->implement('Ray\Aop\WeavedInterface'); |
|
119 | 11 | $builder = $this->addInterceptorProp($builder); |
|
120 | 11 | $builder = $this->addSerialisedAnnotationProp($builder, $class); |
|
121 | |||
122 | 11 | return $builder; |
|
123 | } |
||
124 | |||
125 | /** |
||
126 | * Add class doc comment |
||
127 | * |
||
128 | * @param Class_ $node |
||
129 | * @param \ReflectionClass $class |
||
130 | * |
||
131 | * @return \PhpParser\Node\Stmt\Class_ |
||
132 | */ |
||
133 | 11 | private function addClassDocComment(Class_ $node, \ReflectionClass $class) |
|
134 | { |
||
135 | 11 | $docComment = $class->getDocComment(); |
|
136 | 11 | if ($docComment) { |
|
137 | 9 | $node->setAttribute('comments', [new Doc($docComment)]); |
|
138 | } |
||
139 | |||
140 | 11 | return $node; |
|
141 | } |
||
142 | |||
143 | /** |
||
144 | * @param \ReflectionClass $class |
||
145 | * |
||
146 | * @return string |
||
147 | */ |
||
148 | 11 | private function getClassAnnotation(\ReflectionClass $class) |
|
154 | |||
155 | /** |
||
156 | * @param Builder $builder |
||
157 | * |
||
158 | * @return Builder |
||
159 | */ |
||
160 | 11 | private function addInterceptorProp(Builder $builder) |
|
174 | |||
175 | /** |
||
176 | * Add serialised |
||
177 | * |
||
178 | * @param Builder $builder |
||
179 | * @param \ReflectionClass $class |
||
180 | * |
||
181 | * @return Builder |
||
182 | */ |
||
183 | 11 | private function addSerialisedAnnotationProp(Builder $builder, \ReflectionClass $class) |
|
199 | |||
200 | /** |
||
201 | * @param \ReflectionClass $class |
||
202 | * |
||
203 | * @return string |
||
204 | */ |
||
205 | 11 | private function getMethodAnnotations(\ReflectionClass $class) |
|
219 | } |
||
220 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.