Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 39 and 400]

   1  <?php
   2  
   3  namespace Box\Spout\Autoloader;
   4  
   5  /**
   6   * Class Psr4Autoloader
   7   * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md#class-example
   8   */
   9  class Psr4Autoloader
  10  {
  11      /**
  12       * An associative array where the key is a namespace prefix and the value
  13       * is an array of base directories for classes in that namespace.
  14       *
  15       * @var array
  16       */
  17      protected $prefixes = [];
  18  
  19      /**
  20       * Register loader with SPL autoloader stack.
  21       *
  22       * @return void
  23       */
  24      public function register()
  25      {
  26          \spl_autoload_register([$this, 'loadClass']);
  27      }
  28  
  29      /**
  30       * Adds a base directory for a namespace prefix.
  31       *
  32       * @param string $prefix The namespace prefix.
  33       * @param string $baseDir A base directory for class files in the
  34       * namespace.
  35       * @param bool $prepend If true, prepend the base directory to the stack
  36       * instead of appending it; this causes it to be searched first rather
  37       * than last.
  38       * @return void
  39       */
  40      public function addNamespace($prefix, $baseDir, $prepend = false)
  41      {
  42          // normalize namespace prefix
  43          $prefix = \trim($prefix, '\\') . '\\';
  44  
  45          // normalize the base directory with a trailing separator
  46          $baseDir = \rtrim($baseDir, DIRECTORY_SEPARATOR) . '/';
  47  
  48          // initialize the namespace prefix array
  49          if (isset($this->prefixes[$prefix]) === false) {
  50              $this->prefixes[$prefix] = [];
  51          }
  52  
  53          // retain the base directory for the namespace prefix
  54          if ($prepend) {
  55              \array_unshift($this->prefixes[$prefix], $baseDir);
  56          } else {
  57              \array_push($this->prefixes[$prefix], $baseDir);
  58          }
  59      }
  60  
  61      /**
  62       * Loads the class file for a given class name.
  63       *
  64       * @param string $class The fully-qualified class name.
  65       * @return mixed The mapped file name on success, or boolean false on
  66       * failure.
  67       */
  68      public function loadClass($class)
  69      {
  70          // the current namespace prefix
  71          $prefix = $class;
  72  
  73          // work backwards through the namespace names of the fully-qualified
  74          // class name to find a mapped file name
  75          while (($pos = \strrpos($prefix, '\\')) !== false) {
  76              // retain the trailing namespace separator in the prefix
  77              $prefix = \substr($class, 0, $pos + 1);
  78  
  79              // the rest is the relative class name
  80              $relativeClass = \substr($class, $pos + 1);
  81  
  82              // try to load a mapped file for the prefix and relative class
  83              $mappedFile = $this->loadMappedFile($prefix, $relativeClass);
  84              if ($mappedFile !== false) {
  85                  return $mappedFile;
  86              }
  87  
  88              // remove the trailing namespace separator for the next iteration
  89              // of strrpos()
  90              $prefix = \rtrim($prefix, '\\');
  91          }
  92  
  93          // never found a mapped file
  94          return false;
  95      }
  96  
  97      /**
  98       * Load the mapped file for a namespace prefix and relative class.
  99       *
 100       * @param string $prefix The namespace prefix.
 101       * @param string $relativeClass The relative class name.
 102       * @return mixed Boolean false if no mapped file can be loaded, or the
 103       * name of the mapped file that was loaded.
 104       */
 105      protected function loadMappedFile($prefix, $relativeClass)
 106      {
 107          // are there any base directories for this namespace prefix?
 108          if (isset($this->prefixes[$prefix]) === false) {
 109              return false;
 110          }
 111  
 112          // look through base directories for this namespace prefix
 113          foreach ($this->prefixes[$prefix] as $baseDir) {
 114              // replace the namespace prefix with the base directory,
 115              // replace namespace separators with directory separators
 116              // in the relative class name, append with .php
 117              $file = $baseDir
 118                    . \str_replace('\\', '/', $relativeClass)
 119                    . '.php';
 120  
 121              // if the mapped file exists, require it
 122              if ($this->requireFile($file)) {
 123                  // yes, we're done
 124                  return $file;
 125              }
 126          }
 127  
 128          // never found it
 129          return false;
 130      }
 131  
 132      /**
 133       * If a file exists, require it from the file system.
 134       *
 135       * @param string $file The file to require.
 136       * @return bool True if the file exists, false if not.
 137       */
 138      protected function requireFile($file)
 139      {
 140          if (\file_exists($file)) {
 141              require $file;
 142  
 143              return true;
 144          }
 145  
 146          return false;
 147      }
 148  }