annotate vendor/psy/psysh/src/ExecutionLoop/RunkitReloader.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@13 1 <?php
Chris@13 2
Chris@13 3 /*
Chris@13 4 * This file is part of Psy Shell.
Chris@13 5 *
Chris@13 6 * (c) 2012-2018 Justin Hileman
Chris@13 7 *
Chris@13 8 * For the full copyright and license information, please view the LICENSE
Chris@13 9 * file that was distributed with this source code.
Chris@13 10 */
Chris@13 11
Chris@13 12 namespace Psy\ExecutionLoop;
Chris@13 13
Chris@13 14 use Psy\Exception\ParseErrorException;
Chris@13 15 use Psy\ParserFactory;
Chris@13 16 use Psy\Shell;
Chris@13 17
Chris@13 18 /**
Chris@13 19 * A runkit-based code reloader, which is pretty much magic.
Chris@13 20 */
Chris@13 21 class RunkitReloader extends AbstractListener
Chris@13 22 {
Chris@13 23 private $parser;
Chris@13 24 private $timestamps = [];
Chris@13 25
Chris@13 26 /**
Chris@13 27 * Only enabled if Runkit is installed.
Chris@13 28 *
Chris@13 29 * @return bool
Chris@13 30 */
Chris@13 31 public static function isSupported()
Chris@13 32 {
Chris@17 33 return \extension_loaded('runkit');
Chris@13 34 }
Chris@13 35
Chris@13 36 /**
Chris@13 37 * Construct a Runkit Reloader.
Chris@13 38 *
Chris@13 39 * @todo Pass in Parser Factory instance for dependency injection?
Chris@13 40 */
Chris@13 41 public function __construct()
Chris@13 42 {
Chris@13 43 $parserFactory = new ParserFactory();
Chris@13 44 $this->parser = $parserFactory->createParser();
Chris@13 45 }
Chris@13 46
Chris@13 47 /**
Chris@13 48 * Reload code on input.
Chris@13 49 *
Chris@13 50 * @param Shell $shell
Chris@13 51 * @param string $input
Chris@13 52 */
Chris@13 53 public function onInput(Shell $shell, $input)
Chris@13 54 {
Chris@13 55 $this->reload($shell);
Chris@13 56 }
Chris@13 57
Chris@13 58 /**
Chris@13 59 * Look through included files and update anything with a new timestamp.
Chris@13 60 *
Chris@13 61 * @param Shell $shell
Chris@13 62 */
Chris@13 63 private function reload(Shell $shell)
Chris@13 64 {
Chris@17 65 \clearstatcache();
Chris@13 66 $modified = [];
Chris@13 67
Chris@17 68 foreach (\get_included_files() as $file) {
Chris@17 69 $timestamp = \filemtime($file);
Chris@13 70
Chris@13 71 if (!isset($this->timestamps[$file])) {
Chris@13 72 $this->timestamps[$file] = $timestamp;
Chris@13 73 continue;
Chris@13 74 }
Chris@13 75
Chris@13 76 if ($this->timestamps[$file] === $timestamp) {
Chris@13 77 continue;
Chris@13 78 }
Chris@13 79
Chris@13 80 if (!$this->lintFile($file)) {
Chris@17 81 $msg = \sprintf('Modified file "%s" could not be reloaded', $file);
Chris@13 82 $shell->writeException(new ParseErrorException($msg));
Chris@13 83 continue;
Chris@13 84 }
Chris@13 85
Chris@13 86 $modified[] = $file;
Chris@13 87 $this->timestamps[$file] = $timestamp;
Chris@13 88 }
Chris@13 89
Chris@13 90 // switch (count($modified)) {
Chris@13 91 // case 0:
Chris@13 92 // return;
Chris@13 93
Chris@13 94 // case 1:
Chris@13 95 // printf("Reloading modified file: \"%s\"\n", str_replace(getcwd(), '.', $file));
Chris@13 96 // break;
Chris@13 97
Chris@13 98 // default:
Chris@13 99 // printf("Reloading %d modified files\n", count($modified));
Chris@13 100 // break;
Chris@13 101 // }
Chris@13 102
Chris@13 103 foreach ($modified as $file) {
Chris@13 104 runkit_import($file, (
Chris@13 105 RUNKIT_IMPORT_FUNCTIONS |
Chris@13 106 RUNKIT_IMPORT_CLASSES |
Chris@13 107 RUNKIT_IMPORT_CLASS_METHODS |
Chris@13 108 RUNKIT_IMPORT_CLASS_CONSTS |
Chris@13 109 RUNKIT_IMPORT_CLASS_PROPS |
Chris@13 110 RUNKIT_IMPORT_OVERRIDE
Chris@13 111 ));
Chris@13 112 }
Chris@13 113 }
Chris@13 114
Chris@13 115 /**
Chris@13 116 * Should this file be re-imported?
Chris@13 117 *
Chris@13 118 * Use PHP-Parser to ensure that the file is valid PHP.
Chris@13 119 *
Chris@13 120 * @param string $file
Chris@13 121 *
Chris@13 122 * @return bool
Chris@13 123 */
Chris@13 124 private function lintFile($file)
Chris@13 125 {
Chris@13 126 // first try to parse it
Chris@13 127 try {
Chris@17 128 $this->parser->parse(\file_get_contents($file));
Chris@13 129 } catch (\Exception $e) {
Chris@13 130 return false;
Chris@13 131 }
Chris@13 132
Chris@13 133 return true;
Chris@13 134 }
Chris@13 135 }