public function selectAndLoadSymbols()

in src/symbols/PhutilSymbolLoader.php [165:283]


  public function selectAndLoadSymbols() {
    $map = array();

    $bootloader = PhutilBootloader::getInstance();

    if ($this->library) {
      $libraries = array($this->library);
    } else {
      $libraries = $bootloader->getAllLibraries();
    }

    if ($this->type) {
      $types = array($this->type);
    } else {
      $types = array(
        'class',
        'function',
      );
    }

    $names = null;
    if ($this->base) {
      $names = $this->selectDescendantsOf(
        $bootloader->getClassTree(),
        $this->base);
    }

    $symbols = array();
    foreach ($libraries as $library) {
      $map = $bootloader->getLibraryMap($library);
      foreach ($types as $type) {
        if ($type == 'interface') {
          $lookup_map = $map['class'];
        } else {
          $lookup_map = $map[$type];
        }

        // As an optimization, we filter the list of candidate symbols in
        // several passes, applying a name-based filter first if possible since
        // it is highly selective and guaranteed to match at most one symbol.
        // This is the common case and we land here through `__autoload()` so
        // it's worthwhile to micro-optimize a bit because this code path is
        // very hot and we save 5-10ms per page for a very moderate increase in
        // complexity.

        if ($this->name) {
          // If we have a name filter, just pick the matching name out if it
          // exists.
          if (isset($lookup_map[$this->name])) {
            $filtered_map = array(
              $this->name => $lookup_map[$this->name],
            );
          } else {
            $filtered_map = array();
          }
        } else if ($names !== null) {
          $filtered_map = array();
          foreach ($names as $name => $ignored) {
            if (isset($lookup_map[$name])) {
              $filtered_map[$name] = $lookup_map[$name];
            }
          }
        } else {
          // Otherwise, start with everything.
          $filtered_map = $lookup_map;
        }

        if ($this->pathPrefix) {
          $len = strlen($this->pathPrefix);
          foreach ($filtered_map as $name => $where) {
            if (strncmp($where, $this->pathPrefix, $len) !== 0) {
              unset($filtered_map[$name]);
            }
          }
        }

        foreach ($filtered_map as $name => $where) {
          $symbols[$type.'$'.$name] = array(
            'type'        => $type,
            'name'        => $name,
            'library'     => $library,
            'where'       => $where,
          );
        }
      }
    }

    if (!$this->suppressLoad) {
      $caught = null;
      foreach ($symbols as $symbol) {
        try {
          $this->loadSymbol($symbol);
        } catch (Exception $ex) {
          $caught = $ex;
        }
      }
      if ($caught) {
        // NOTE: We try to load everything even if we fail to load something,
        // primarily to make it possible to remove functions from a libphutil
        // library without breaking library startup.
        throw $caught;
      }
    }


    if ($this->concrete) {
      // Remove 'abstract' classes.
      foreach ($symbols as $key => $symbol) {
        if ($symbol['type'] == 'class') {
          $reflection = new ReflectionClass($symbol['name']);
          if ($reflection->isAbstract()) {
            unset($symbols[$key]);
          }
        }
      }
    }

    return $symbols;
  }