TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

94 lines
2.5 KiB

<?php
namespace PhpAot\Php;
class FileSorter
{
private array $functionDeclInFile;
private array $functionCallInFile;
public function __construct(array $functionDeclInFile, array $functionCallInFile)
{
$this->functionDeclInFile = $functionDeclInFile;
$this->functionCallInFile = $functionCallInFile;
}
public function sort(): array
{
$dependencies = $this->buildDependencies();
$allFiles = $this->getAllFiles();
$inDegree = array_fill_keys($allFiles, 0);
foreach ($dependencies as $deps) {
foreach ($deps as $dep) {
$inDegree[$dep]++;
}
}
$queue = [];
foreach ($inDegree as $file => $degree) {
if ($degree === 0) {
$queue[] = $file;
}
}
$sorted = [];
while (!empty($queue)) {
$current = array_shift($queue);
$sorted[] = $current;
if (isset($dependencies[$current])) {
foreach ($dependencies[$current] as $dep) {
$inDegree[$dep]--;
if ($inDegree[$dep] === 0) {
$queue[] = $dep;
}
}
}
}
if (count($sorted) !== count($allFiles)) {
throw new \RuntimeException("Circular dependency of function call detected");
}
return array_reverse($sorted);
}
private function buildDependencies(): array
{
$dependencies = [];
foreach ($this->functionCallInFile as $call) {
$callerFile = $call['file'];
$functionName = $call['name'];
if (isset($this->functionDeclInFile[$functionName])) {
$declFile = $this->functionDeclInFile[$functionName];
if ($callerFile !== $declFile) {
if (!isset($dependencies[$callerFile])) {
$dependencies[$callerFile] = [];
}
if (!in_array($declFile, $dependencies[$callerFile])) {
$dependencies[$callerFile][] = $declFile;
}
}
}
}
return $dependencies;
}
private function getAllFiles(): array
{
$files = array_values($this->functionDeclInFile);
foreach ($this->functionCallInFile as $call) {
$files[] = $call['file'];
}
return array_unique($files);
}
}