reportedOperations[] = $file . ' - include'; } /** * @var string */ protected $instanceKey; /** * @var string[] */ protected $knownPaths = array(); /** * @var string[] */ protected $reportedOperations = array(); const NOTHING = FALSE; const DIR = '(dir)'; const FILE = '(file)'; function __construct() { $this->instanceKey = Util::randomString(); self::$instances[$this->instanceKey] = $this; } /** * @return array[] */ function getReportedOperations() { return $this->reportedOperations; } /** * Delete all reported operations and start fresh. */ function resetReportedOperations() { $this->reportedOperations = array(); } /** * @param string $file * @param string $class * @throws \Exception */ function addClass($file, $class) { $this->addKnownFile($file); if (self::FILE !== ($existing = $this->knownPaths[$file])) { throw new \Exception("A non-empty file already exists at '$file'. Cannot overwrite with class '$class'."); } $this->knownPaths[$file] = $class; } /** * @param string $file * @param string $php * File contents starting with 'addKnownFile($file); if (!$overwrite && self::FILE !== ($existing = $this->knownPaths[$file])) { throw new \Exception("A non-empty file already exists at '$file'. Cannot overwrite with PHP code."); } if (0 !== strpos($php, 'knownPaths[$file] = $php; } /** * @param string[] $files */ function addKnownFiles(array $files) { foreach ($files as $file) { $this->addKnownFile($file); } } /** * @param string $file * * @throws \Exception */ function addKnownFile($file) { if (!isset($this->knownPaths[$file])) { $this->knownPaths[$file] = self::FILE; $this->addKnownDir(dirname($file)); } elseif (self::DIR === $this->knownPaths[$file]) { throw new \Exception("A directory already exists at '$file', cannot overwrite with a file."); } } /** * @param string $dir */ function addKnownDir($dir) { if (FALSE === strpos($dir, '://')) { return; } if (!isset($this->knownPaths[$dir])) { // Need to set parents first. $this->addKnownDir(dirname($dir)); } $this->knownPaths[$dir] = self::DIR; } /** * @param string $path * @return string|bool * One of self::NOTHING, self::DIR, self::FILE, or a class name for a class * that is supposed to be defined in the file. */ function resolvePath($path) { if (isset($this->knownPaths[$path])) { return $this->knownPaths[$path]; } else { return self::NOTHING; } } /** * @param string $dir * @return array|bool */ function getDirContents($dir) { if (empty($this->knownPaths[$dir]) || self::DIR !== $this->knownPaths[$dir]) { return FALSE; } $pos = strlen($dir . '/'); $contents = array('.', '..'); foreach ($this->knownPaths as $path => $type) { if ($dir . '/' !== substr($path, 0, $pos)) { continue; } $name = substr($path, $pos); if (FALSE !== strpos($name, '/')) { // This is a deeper subdirectory. continue; } if ('' === $name) { continue; } $contents[] = $name; } return $contents; } /** * @param string $path * @param bool $report * * @return array */ function getStat($path, $report = TRUE) { if ($report) { $this->reportedOperations[] = $path . ' - stat'; } if (!isset($this->knownPaths[$path])) { // File does not exist. return FALSE; } elseif (self::DIR === $this->knownPaths[$path]) { return stat(__DIR__); } else { // Create a tmp file with the contents and get its stats. $contents = $this->getFileContents($path); $resource = tmpfile(); fwrite($resource, $contents); $stat = fstat($resource); fclose($resource); return $stat; } } /** * @param $path * The file path. * * @return string * The file contents. * * @throws \Exception * Exception thrown if there is no file at $path. */ function getFileContents($path) { if (!isset($this->knownPaths[$path])) { // File does not exist. throw new \Exception("Assumed file '$path' does not exist."); } elseif (self::DIR === $this->knownPaths[$path]) { throw new \Exception("Assumed file '$path' is a directory."); } $instance_key_export = var_export($this->instanceKey, TRUE); $path_export = var_export($path, TRUE); if (self::FILE === $this->knownPaths[$path]) { // Empty PHP file.. return <<knownPaths[$path], 'knownPaths[$path], 5); return <<knownPaths[$path])) { // File with arbitrary contents. return $this->knownPaths[$path]; } // PHP file with class definition. $class = $this->knownPaths[$path]; if (FALSE === ($pos = strrpos($class, '\\'))) { // Class without namespace. return <<