|
1
|
|
|
<?php |
|
2
|
|
|
/* |
|
3
|
|
|
* The MIT License (MIT) |
|
4
|
|
|
* |
|
5
|
|
|
* Copyright (c) 2015 zepi |
|
6
|
|
|
* |
|
7
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
8
|
|
|
* of this software and associated documentation files (the "Software"), to deal |
|
9
|
|
|
* in the Software without restriction, including without limitation the rights |
|
10
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
11
|
|
|
* copies of the Software, and to permit persons to whom the Software is |
|
12
|
|
|
* furnished to do so, subject to the following conditions: |
|
13
|
|
|
* |
|
14
|
|
|
* The above copyright notice and this permission notice shall be included in |
|
15
|
|
|
* all copies or substantial portions of the Software. |
|
16
|
|
|
* |
|
17
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
18
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
19
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
20
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
21
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
22
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
23
|
|
|
* THE SOFTWARE. |
|
24
|
|
|
* |
|
25
|
|
|
*/ |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* The Framework object delivers the root functionality for |
|
29
|
|
|
* zepi Turbo. |
|
30
|
|
|
* |
|
31
|
|
|
* @package Zepi\Turbo |
|
32
|
|
|
* @author Matthias Zobrist <[email protected]> |
|
33
|
|
|
* @copyright Copyright (c) 2015 zepi |
|
34
|
|
|
*/ |
|
35
|
|
|
|
|
36
|
|
|
namespace Zepi\Turbo; |
|
37
|
|
|
|
|
38
|
|
|
use \Zepi\Turbo\Manager\DataSourceManager; |
|
39
|
|
|
use \Zepi\Turbo\Manager\ModuleManager; |
|
40
|
|
|
use \Zepi\Turbo\Manager\RuntimeManager; |
|
41
|
|
|
use \Zepi\Turbo\Manager\RouteManager; |
|
42
|
|
|
use \Zepi\Turbo\Manager\RequestManager; |
|
43
|
|
|
use \Zepi\Turbo\Request\RequestAbstract; |
|
44
|
|
|
use \Zepi\Turbo\Response\Response; |
|
45
|
|
|
use Zepi\Turbo\Manager\Zepi\Turbo\Manager; |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* The Framework object delivers the root functionality for |
|
49
|
|
|
* zepi Turbo. |
|
50
|
|
|
* |
|
51
|
|
|
* @author Matthias Zobrist <[email protected]> |
|
52
|
|
|
* @copyright Copyright (c) 2015 zepi |
|
53
|
|
|
*/ |
|
54
|
|
|
class Framework |
|
55
|
|
|
{ |
|
56
|
|
|
/** |
|
57
|
|
|
* @static |
|
58
|
|
|
* @access protected |
|
59
|
|
|
* @var Framework |
|
60
|
|
|
*/ |
|
61
|
|
|
static protected $instance; |
|
62
|
|
|
|
|
63
|
|
|
/** |
|
64
|
|
|
* @access protected |
|
65
|
|
|
* @var string |
|
66
|
|
|
*/ |
|
67
|
|
|
protected $rootDirectory; |
|
68
|
|
|
|
|
69
|
|
|
/** |
|
70
|
|
|
* @access protected |
|
71
|
|
|
* @var array |
|
72
|
|
|
*/ |
|
73
|
|
|
protected $moduleDirectories = array(); |
|
74
|
|
|
|
|
75
|
|
|
/** |
|
76
|
|
|
* @access protected |
|
77
|
|
|
* @var array |
|
78
|
|
|
*/ |
|
79
|
|
|
protected $moduleNamespaces = array(); |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* @access protected |
|
83
|
|
|
* @var array |
|
84
|
|
|
*/ |
|
85
|
|
|
protected $modules = array(); |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* @access protected |
|
89
|
|
|
* @var \Zepi\Turbo\Manager\DataSourceManager |
|
90
|
|
|
*/ |
|
91
|
|
|
protected $dataSourceManager; |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* @access protected |
|
95
|
|
|
* @var \Zepi\Turbo\Manager\ModuleManager |
|
96
|
|
|
*/ |
|
97
|
|
|
protected $moduleManager; |
|
98
|
|
|
|
|
99
|
|
|
/** |
|
100
|
|
|
* @access protected |
|
101
|
|
|
* @var \Zepi\Turbo\Manager\RuntimeManager |
|
102
|
|
|
*/ |
|
103
|
|
|
protected $runtimeManager; |
|
104
|
|
|
|
|
105
|
|
|
/** |
|
106
|
|
|
* @access protected |
|
107
|
|
|
* @var \Zepi\Turbo\Manager\RouteManager |
|
108
|
|
|
*/ |
|
109
|
|
|
protected $routeManager; |
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* @access protected |
|
113
|
|
|
* @var \Zepi\Turbo\Manager\RequestManager |
|
114
|
|
|
*/ |
|
115
|
|
|
protected $requestManager; |
|
116
|
|
|
|
|
117
|
|
|
/** |
|
118
|
|
|
* @access protected |
|
119
|
|
|
* @var \Zepi\Turbo\Request\RequestAbstract |
|
120
|
|
|
*/ |
|
121
|
|
|
protected $request; |
|
122
|
|
|
|
|
123
|
|
|
/** |
|
124
|
|
|
* @access protected |
|
125
|
|
|
* @var \Zepi\Turbo\Response\Response |
|
126
|
|
|
*/ |
|
127
|
|
|
protected $response; |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* Constructs the object |
|
131
|
|
|
* |
|
132
|
|
|
* @access private |
|
133
|
|
|
* @param string $rootDirectory |
|
134
|
|
|
*/ |
|
135
|
|
|
private function __construct($rootDirectory) |
|
136
|
|
|
{ |
|
137
|
|
|
$this->rootDirectory = $rootDirectory; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
/** |
|
141
|
|
|
* Returns a instance of the Framework |
|
142
|
|
|
* |
|
143
|
|
|
* @static |
|
144
|
|
|
* @access public |
|
145
|
|
|
* @param string $rootDirectory |
|
146
|
|
|
* @return Framework |
|
147
|
|
|
*/ |
|
148
|
|
|
public static function getFrameworkInstance($rootDirectory) |
|
149
|
|
|
{ |
|
150
|
|
|
if (self::$instance === null) { |
|
151
|
|
|
self::$instance = new Framework($rootDirectory); |
|
152
|
|
|
self::$instance->initializeFramework(); |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
return self::$instance; |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
|
|
/** |
|
159
|
|
|
* Resets the framework |
|
160
|
|
|
* |
|
161
|
|
|
* @static |
|
162
|
|
|
* @access public |
|
163
|
|
|
*/ |
|
164
|
|
|
public static function resetFramework() |
|
165
|
|
|
{ |
|
166
|
|
|
self::$instance = null; |
|
167
|
|
|
} |
|
168
|
|
|
|
|
169
|
|
|
/** |
|
170
|
|
|
* Returns the path to the framework directory. |
|
171
|
|
|
* |
|
172
|
|
|
* @access public |
|
173
|
|
|
* @return string |
|
174
|
|
|
*/ |
|
175
|
|
|
public function getRootDirectory() |
|
176
|
|
|
{ |
|
177
|
|
|
return $this->rootDirectory; |
|
178
|
|
|
} |
|
179
|
|
|
|
|
180
|
|
|
/** |
|
181
|
|
|
* Initializes the framework and creates all needed managers. |
|
182
|
|
|
* |
|
183
|
|
|
* @access protected |
|
184
|
|
|
*/ |
|
185
|
|
|
protected function initializeFramework() |
|
186
|
|
|
{ |
|
187
|
|
|
$this->registerAutoloader(); |
|
188
|
|
|
|
|
189
|
|
|
$this->requestManager = new RequestManager($this); |
|
190
|
|
|
$this->request = $this->requestManager->buildRequest(); |
|
191
|
|
|
|
|
192
|
|
|
$this->response = new Response($this->request); |
|
193
|
|
|
|
|
194
|
|
|
$this->dataSourceManager = new DataSourceManager($this, $this->getInstance('Zepi\\Turbo\\Backend\\VirtualDataSourceBackend')); |
|
195
|
|
|
$this->dataSourceManager->initializeDataSourceManager(); |
|
196
|
|
|
|
|
197
|
|
|
$this->moduleManager = new ModuleManager($this, $this->getInstance('Zepi\\Turbo\\Backend\\VirtualModuleBackend')); |
|
198
|
|
|
$this->moduleManager->initializeModuleSystem(); |
|
199
|
|
|
|
|
200
|
|
|
$this->runtimeManager = new RuntimeManager($this, $this->getInstance('Zepi\\Turbo\\Backend\\VirtualHandlerBackend')); |
|
201
|
|
|
$this->runtimeManager->initializeManager(); |
|
202
|
|
|
|
|
203
|
|
|
$this->routeManager = new RouteManager($this, $this->getInstance('Zepi\\Turbo\\Backend\\VirtualRouteBackend')); |
|
204
|
|
|
$this->routeManager->initializeRoutingTable(); |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
/** |
|
208
|
|
|
* Returns the data source manager for the framework |
|
209
|
|
|
* |
|
210
|
|
|
* @access public |
|
211
|
|
|
* @return \Zepi\Turbo\Manager\DataSourceManager |
|
212
|
|
|
*/ |
|
213
|
|
|
public function getDataSourceManager() |
|
214
|
|
|
{ |
|
215
|
|
|
return $this->dataSourceManager; |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
/** |
|
219
|
|
|
* Returns the module manager for the framework |
|
220
|
|
|
* |
|
221
|
|
|
* @access public |
|
222
|
|
|
* @return \Zepi\Turbo\Manager\ModuleManager |
|
223
|
|
|
*/ |
|
224
|
|
|
public function getModuleManager() |
|
225
|
|
|
{ |
|
226
|
|
|
return $this->moduleManager; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
/** |
|
230
|
|
|
* Returns the runtime manager for the framework |
|
231
|
|
|
* |
|
232
|
|
|
* @access public |
|
233
|
|
|
* @return \Zepi\Turbo\Manager\RuntimeManager |
|
234
|
|
|
*/ |
|
235
|
|
|
public function getRuntimeManager() |
|
236
|
|
|
{ |
|
237
|
|
|
return $this->runtimeManager; |
|
238
|
|
|
} |
|
239
|
|
|
|
|
240
|
|
|
/** |
|
241
|
|
|
* Returns the route manager for the framework |
|
242
|
|
|
* |
|
243
|
|
|
* @access public |
|
244
|
|
|
* @return \Zepi\Turbo\Manager\RouteManager |
|
245
|
|
|
*/ |
|
246
|
|
|
public function getRouteManager() |
|
247
|
|
|
{ |
|
248
|
|
|
return $this->routeManager; |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
/** |
|
252
|
|
|
* Returns the RequestManager object |
|
253
|
|
|
* |
|
254
|
|
|
* @access public |
|
255
|
|
|
* @return \Zepi\Turbo\Manager\RequestManager |
|
256
|
|
|
*/ |
|
257
|
|
|
public function getRequestManager() |
|
258
|
|
|
{ |
|
259
|
|
|
return $this->requestManager; |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
/** |
|
263
|
|
|
* Returns the request object for the request |
|
264
|
|
|
* |
|
265
|
|
|
* @access public |
|
266
|
|
|
* @return \Zepi\Turbo\Request\RequestAbstract |
|
267
|
|
|
*/ |
|
268
|
|
|
public function getRequest() |
|
269
|
|
|
{ |
|
270
|
|
|
return $this->request; |
|
271
|
|
|
} |
|
272
|
|
|
|
|
273
|
|
|
/** |
|
274
|
|
|
* Returns the response for the request |
|
275
|
|
|
* |
|
276
|
|
|
* @access public |
|
277
|
|
|
* @return \Zepi\Turbo\Response\Response |
|
278
|
|
|
*/ |
|
279
|
|
|
public function getResponse() |
|
280
|
|
|
{ |
|
281
|
|
|
return $this->response; |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
/** |
|
285
|
|
|
* Registers the global autloader. |
|
286
|
|
|
* |
|
287
|
|
|
* @access protected |
|
288
|
|
|
*/ |
|
289
|
|
|
protected function registerAutoloader() |
|
290
|
|
|
{ |
|
291
|
|
|
spl_autoload_register(array($this, 'loadClass')); |
|
292
|
|
|
} |
|
293
|
|
|
|
|
294
|
|
|
/** |
|
295
|
|
|
* Prepares the class name and adds a backslash in front |
|
296
|
|
|
* of the class name if there isn't a bachslash. |
|
297
|
|
|
* |
|
298
|
|
|
* @static |
|
299
|
|
|
* @access public |
|
300
|
|
|
* @param string $className |
|
301
|
|
|
* @return string |
|
302
|
|
|
*/ |
|
303
|
|
|
public static function prepareClassName($className) |
|
304
|
|
|
{ |
|
305
|
|
|
if (substr($className, 0, 1) !== '\\') { |
|
306
|
|
|
$className = '\\' . $className; |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
return $className; |
|
310
|
|
|
} |
|
311
|
|
|
|
|
312
|
|
|
/** |
|
313
|
|
|
* Prepares the namespace and adds on both sides of the |
|
314
|
|
|
* namespace the backslashes. |
|
315
|
|
|
* |
|
316
|
|
|
* @static |
|
317
|
|
|
* @access public |
|
318
|
|
|
* @param string $namespace |
|
319
|
|
|
* @return string |
|
320
|
|
|
*/ |
|
321
|
|
|
public static function prepareNamespace($namespace) |
|
322
|
|
|
{ |
|
323
|
|
|
if (substr($namespace, 0, 1) !== '\\') { |
|
324
|
|
|
$namespace = '\\' . $namespace; |
|
325
|
|
|
} |
|
326
|
|
|
|
|
327
|
|
|
if (substr($namespace, -1) !== '\\') { |
|
328
|
|
|
$namespace .= '\\'; |
|
329
|
|
|
} |
|
330
|
|
|
|
|
331
|
|
|
return $namespace; |
|
332
|
|
|
} |
|
333
|
|
|
|
|
334
|
|
|
/** |
|
335
|
|
|
* Framework autoloader: This function is called from the SPL Autoloader |
|
336
|
|
|
* to load the correct class. If the class isn't in the framework the |
|
337
|
|
|
* function will trying to load and initialize the module. |
|
338
|
|
|
* |
|
339
|
|
|
* @access public |
|
340
|
|
|
* @param string $className |
|
341
|
|
|
* |
|
342
|
|
|
* @throws \Exception Cannot find the class "$className"! |
|
343
|
|
|
*/ |
|
344
|
|
|
public function loadClass($className) |
|
345
|
|
|
{ |
|
346
|
|
|
$path = false; |
|
347
|
|
|
$module = false; |
|
348
|
|
|
$className = self::prepareClassName($className); |
|
349
|
|
|
|
|
350
|
|
|
if (strpos($className, '\\Zepi\\Turbo\\') === 0) { |
|
351
|
|
|
$sourceDirectory = realpath(__DIR__ . '/../../'); |
|
352
|
|
|
|
|
353
|
|
|
// The class is from the framework, so we load the class file from the framework directory |
|
354
|
|
|
$path = $sourceDirectory . str_replace('\\', '/', $className) . '.php'; |
|
355
|
|
|
} else { |
|
356
|
|
|
// The class isn't from the framework, so we need the module for the given class name |
|
357
|
|
|
$module = $this->moduleManager->getModuleByClassName($className); |
|
358
|
|
|
|
|
359
|
|
|
if ($module !== false) { |
|
360
|
|
|
$fileName = substr($className, strlen($module->getNamespace())); |
|
361
|
|
|
$path = $module->getDirectory() . '/src/' . str_replace('\\', '/', $fileName) . '.php'; |
|
362
|
|
|
} |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
if ($path !== false && file_exists($path)) { |
|
366
|
|
|
require_once($path); |
|
367
|
|
|
} else if ($module !== false) { |
|
368
|
|
|
throw new Exception('Cannot find the class "' . $className . '"!'); |
|
369
|
|
|
} |
|
370
|
|
|
} |
|
371
|
|
|
|
|
372
|
|
|
/** |
|
373
|
|
|
* Returns an instance of an object. If the module for the object |
|
374
|
|
|
* isn't initialized, the function will load the module and |
|
375
|
|
|
* initialize the module. |
|
376
|
|
|
* |
|
377
|
|
|
* @access public |
|
378
|
|
|
* @param string $className |
|
379
|
|
|
* @return mixed |
|
380
|
|
|
* |
|
381
|
|
|
* @throws \Zepi\Turbo\Exception Cannot find the module for the given class name. |
|
382
|
|
|
* @throws \Zepi\Turbo\Exception Instance isn't an object! |
|
383
|
|
|
*/ |
|
384
|
|
|
public function getInstance($className) |
|
385
|
|
|
{ |
|
386
|
|
|
$className = self::prepareClassName($className); |
|
387
|
|
|
|
|
388
|
|
|
if (strpos($className, '\\Zepi\\Turbo') === 0) { |
|
389
|
|
|
$instance = $this->getCoreInstance($className); |
|
390
|
|
|
} else { |
|
391
|
|
|
$module = $this->moduleManager->getModuleByClassName($className); |
|
392
|
|
|
|
|
393
|
|
|
if ($module === false) { |
|
394
|
|
|
throw new Exception('Cannot find the module for the given class name "' . $className . '".'); |
|
395
|
|
|
} |
|
396
|
|
|
|
|
397
|
|
|
$instance = $module->getInstance($className); |
|
398
|
|
|
} |
|
399
|
|
|
|
|
400
|
|
|
if (!is_object($instance)) { |
|
401
|
|
|
throw new Exception('Instance for class name "' . $className . '" isn\'t an object!'); |
|
402
|
|
|
} |
|
403
|
|
|
|
|
404
|
|
|
return $instance; |
|
405
|
|
|
} |
|
406
|
|
|
|
|
407
|
|
|
/** |
|
408
|
|
|
* Returns the instance of a framework object |
|
409
|
|
|
* |
|
410
|
|
|
* @access protected |
|
411
|
|
|
* @param string $className |
|
412
|
|
|
* @return mixed |
|
413
|
|
|
* |
|
414
|
|
|
* @throws \Zepi\Turbo\Exception Class "{className}" is not defined. |
|
415
|
|
|
*/ |
|
416
|
|
|
protected function getCoreInstance($className) |
|
417
|
|
|
{ |
|
418
|
|
|
$className = self::prepareClassName($className); |
|
419
|
|
|
|
|
420
|
|
|
switch ($className) { |
|
421
|
|
|
case '\\Zepi\\Turbo\\Backend\\VirtualModuleBackend': |
|
422
|
|
|
$path = $this->rootDirectory . '/data/modules.data'; |
|
423
|
|
|
return new \Zepi\Turbo\Backend\FileObjectBackend($path); |
|
424
|
|
|
break; |
|
425
|
|
|
case '\\Zepi\\Turbo\\Backend\\VirtualHandlerBackend': |
|
426
|
|
|
$path = $this->rootDirectory . '/data/handlers.data'; |
|
427
|
|
|
return new \Zepi\Turbo\Backend\FileObjectBackend($path); |
|
428
|
|
|
break; |
|
429
|
|
|
case '\\Zepi\\Turbo\\Backend\\VirtualRouteBackend': |
|
430
|
|
|
$path = $this->rootDirectory . '/data/routes.data'; |
|
431
|
|
|
return new \Zepi\Turbo\Backend\FileObjectBackend($path); |
|
432
|
|
|
break; |
|
433
|
|
|
case '\\Zepi\\Turbo\\Backend\\VirtualDataSourceBackend': |
|
434
|
|
|
$path = $this->rootDirectory . '/data/data-sources.data'; |
|
435
|
|
|
return new \Zepi\Turbo\Backend\FileObjectBackend($path); |
|
436
|
|
|
break; |
|
437
|
|
|
default: |
|
438
|
|
|
if (class_exists($className, true)) { |
|
439
|
|
|
return new $className(); |
|
440
|
|
|
} else { |
|
441
|
|
|
throw new Exception('Class "' . $className . '" is not defined.'); |
|
442
|
|
|
} |
|
443
|
|
|
break; |
|
|
|
|
|
|
444
|
|
|
} |
|
445
|
|
|
} |
|
446
|
|
|
|
|
447
|
|
|
/** |
|
448
|
|
|
* Executes the framework. This executes the pre and post execution events. |
|
449
|
|
|
* Between these two events we call the correct request event. The |
|
450
|
|
|
* routing table from the RouteManager returns the needed event name. |
|
451
|
|
|
* |
|
452
|
|
|
* @access public |
|
453
|
|
|
*/ |
|
454
|
|
|
public function execute() |
|
455
|
|
|
{ |
|
456
|
|
|
// Execute the before execution event |
|
457
|
|
|
$this->runtimeManager->executeEvent('\\Zepi\\Turbo\\Event\\BeforeExecution'); |
|
458
|
|
|
|
|
459
|
|
|
// Get the event name for the request and execute the event |
|
460
|
|
|
$eventName = $this->routeManager->getEventNameForRoute($this->request); |
|
461
|
|
|
$eventName = $this->runtimeManager->executeFilter('\\Zepi\\Turbo\\Filter\\VerifyEventName', $eventName); |
|
462
|
|
|
|
|
463
|
|
|
if ($eventName !== false && $eventName != '') { |
|
464
|
|
|
$this->runtimeManager->executeEvent($eventName); |
|
465
|
|
|
} else { |
|
466
|
|
|
$this->runtimeManager->executeEvent('\\Zepi\\Turbo\\Event\\RouteNotFound'); |
|
467
|
|
|
} |
|
468
|
|
|
|
|
469
|
|
|
// Execute the after execution event |
|
470
|
|
|
$this->runtimeManager->executeEvent('\\Zepi\\Turbo\\Event\\AfterExecution'); |
|
471
|
|
|
|
|
472
|
|
|
// Finalize the output |
|
473
|
|
|
$this->runtimeManager->executeEvent('\\Zepi\\Turbo\\Event\\FinalizeOutput'); |
|
474
|
|
|
|
|
475
|
|
|
// Execute the before output event |
|
476
|
|
|
$this->runtimeManager->executeEvent('\\Zepi\\Turbo\\Event\\BeforeOutput'); |
|
477
|
|
|
|
|
478
|
|
|
// Print the output |
|
479
|
|
|
echo $this->response->getOutput(); |
|
480
|
|
|
|
|
481
|
|
|
// Execute the after output event |
|
482
|
|
|
$this->runtimeManager->executeEvent('\\Zepi\\Turbo\\Event\\AfterOutput'); |
|
483
|
|
|
} |
|
484
|
|
|
} |
|
485
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return,dieorexitstatements that have been added for debug purposes.In the above example, the last
return falsewill never be executed, because a return statement has already been met in every possible execution path.