Phan\Ordering::orderForProcessCount PHP Method

orderForProcessCount() public method

public orderForProcessCount ( integer $process_count, array $analysis_file_list ) : array
$process_count integer The number of processes we'd like to divide work up amongst.
$analysis_file_list array A list of files that should be analyzed which will be used to ignore any files outside of the list and to draw from for any missing files.
return array A map from process_id to a list of files to be analyzed on that process in stable ordering.
    public function orderForProcessCount(int $process_count, array $analysis_file_list) : array
    {
        assert($process_count > 0, "The process count must be greater than zero.");
        if (Config::get()->randomize_file_order) {
            $random_proc_file_map = [];
            $i = 0;
            shuffle($analysis_file_list);
            foreach ($analysis_file_list as $i => $file) {
                $random_proc_file_map[$i++ % $process_count][] = $file;
            }
            return $random_proc_file_map;
        }
        // Construct a Hasher implementation based on config.
        if (Config::get()->consistent_hashing_file_order) {
            sort($analysis_file_list, SORT_STRING);
            $hasher = new Consistent($process_count);
        } else {
            $hasher = new Sequential($process_count);
        }
        // Create a Set from the file list
        $analysis_file_map = [];
        foreach ($analysis_file_list as $i => $file) {
            $analysis_file_map[$file] = true;
        }
        // A map from the root of an object hierarchy to all
        // elements within that hierarchy
        $root_fqsen_list = [];
        $file_names_for_classes = [];
        // Iterate over each class extracting files
        foreach ($this->code_base->getClassMap() as $fqsen => $class) {
            // We won't be analyzing internal stuff
            if ($class->isInternal()) {
                continue;
            }
            // Get the name of the file associated with the class
            $file_name = $class->getContext()->getFile();
            // Ignore any files that are not to be analyzed
            if (!isset($analysis_file_map[$file_name])) {
                continue;
            }
            unset($analysis_file_map[$file_name]);
            $file_names_for_classes[$file_name] = $class;
        }
        if (Config::get()->consistent_hashing_file_order) {
            ksort($file_names_for_classes, SORT_STRING);
        }
        foreach ($file_names_for_classes as $file_name => $class) {
            // Get the class's depth in its object hierarchy and
            // the FQSEN of the object at the root of its hierarchy
            $hierarchy_depth = $class->getHierarchyDepth($this->code_base);
            $hierarchy_root = $class->getHierarchyRootFQSEN($this->code_base);
            // Create a bucket for this root if it doesn't exist
            if (empty($root_fqsen_list[(string) $hierarchy_root])) {
                $root_fqsen_list[(string) $hierarchy_root] = [];
            }
            // Append this {file,depth} pair to the hierarchy
            // root
            $root_fqsen_list[(string) $hierarchy_root][] = ['file' => $file_name, 'depth' => $hierarchy_depth];
        }
        // Create a map from processor_id to the list of files
        // to be analyzed on that processor
        $processor_file_list_map = [];
        // Sort the set of files with a given root by their
        // depth in the hierarchy
        foreach ($root_fqsen_list as $root_fqsen => $list) {
            // Sort first by depth, and break ties by file name lexicographically
            // (usort is not a stable sort).
            usort($list, function (array $a, array $b) {
                return $a['depth'] <=> $b['depth'] ?: strcmp($a['file'], $b['file']);
            });
            // Choose which process this file list will be
            // run on
            $process_id = $hasher->getGroup((string) $root_fqsen);
            // Append each file to this process list
            foreach ($list as $item) {
                $processor_file_list_map[$process_id][] = $item['file'];
            }
        }
        // Distribute any remaining files without classes evenly
        // between the processes
        $hasher->reset();
        foreach (array_keys($analysis_file_map) as $file) {
            // Choose which process this file list will be
            // run on
            $process_id = $hasher->getGroup((string) $file);
            $processor_file_list_map[$process_id][] = $file;
        }
        return $processor_file_list_map;
    }