4 * This file is part of Psy Shell.
6 * (c) 2012-2018 Justin Hileman
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Psy\ExecutionLoop;
14 use Psy\Exception\ParseErrorException;
15 use Psy\ParserFactory;
19 * A runkit-based code reloader, which is pretty much magic.
21 class RunkitReloader extends AbstractListener
24 private $timestamps = [];
27 * Only enabled if Runkit is installed.
31 public static function isSupported()
33 return extension_loaded('runkit');
37 * Construct a Runkit Reloader.
39 * @todo Pass in Parser Factory instance for dependency injection?
41 public function __construct()
43 $parserFactory = new ParserFactory();
44 $this->parser = $parserFactory->createParser();
48 * Reload code on input.
51 * @param string $input
53 public function onInput(Shell $shell, $input)
55 $this->reload($shell);
59 * Look through included files and update anything with a new timestamp.
63 private function reload(Shell $shell)
68 foreach (get_included_files() as $file) {
69 $timestamp = filemtime($file);
71 if (!isset($this->timestamps[$file])) {
72 $this->timestamps[$file] = $timestamp;
76 if ($this->timestamps[$file] === $timestamp) {
80 if (!$this->lintFile($file)) {
81 $msg = sprintf('Modified file "%s" could not be reloaded', $file);
82 $shell->writeException(new ParseErrorException($msg));
87 $this->timestamps[$file] = $timestamp;
90 // switch (count($modified)) {
95 // printf("Reloading modified file: \"%s\"\n", str_replace(getcwd(), '.', $file));
99 // printf("Reloading %d modified files\n", count($modified));
103 foreach ($modified as $file) {
104 runkit_import($file, (
105 RUNKIT_IMPORT_FUNCTIONS |
106 RUNKIT_IMPORT_CLASSES |
107 RUNKIT_IMPORT_CLASS_METHODS |
108 RUNKIT_IMPORT_CLASS_CONSTS |
109 RUNKIT_IMPORT_CLASS_PROPS |
110 RUNKIT_IMPORT_OVERRIDE
116 * Should this file be re-imported?
118 * Use PHP-Parser to ensure that the file is valid PHP.
120 * @param string $file
124 private function lintFile($file)
126 // first try to parse it
128 $this->parser->parse(file_get_contents($file));
129 } catch (\Exception $e) {