mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-13 20:05:35 +08:00
Implement caching for config file parsing to improve performance
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -67,3 +67,6 @@ spc.exe
|
|||||||
|
|
||||||
# dumped files from StaticPHP v3
|
# dumped files from StaticPHP v3
|
||||||
/dump-*.json
|
/dump-*.json
|
||||||
|
|
||||||
|
# config parse cache
|
||||||
|
/.spc.cache.php
|
||||||
|
|||||||
@@ -42,13 +42,22 @@ class ArtifactConfig
|
|||||||
if ($content === false) {
|
if ($content === false) {
|
||||||
throw new WrongUsageException("Failed to read artifact config file: {$file}");
|
throw new WrongUsageException("Failed to read artifact config file: {$file}");
|
||||||
}
|
}
|
||||||
$data = match (pathinfo($file, PATHINFO_EXTENSION)) {
|
// use cache to skip redundant parsing
|
||||||
'json' => json_decode($content, true),
|
$data = ConfigCache::get($content);
|
||||||
'yml', 'yaml' => Yaml::parse($content),
|
if ($data !== null) {
|
||||||
default => throw new WrongUsageException("Unsupported artifact config file format: {$file}"),
|
logger()->debug("Config cache hit: {$file}");
|
||||||
};
|
} else {
|
||||||
if (!is_array($data)) {
|
$data = match (pathinfo($file, PATHINFO_EXTENSION)) {
|
||||||
throw new WrongUsageException("Invalid JSON format in artifact config file: {$file}");
|
'json' => json_decode($content, true),
|
||||||
|
'yml', 'yaml' => extension_loaded('yaml') ? yaml_parse($content) : Yaml::parse($content),
|
||||||
|
default => throw new WrongUsageException("Unsupported artifact config file format: {$file}"),
|
||||||
|
};
|
||||||
|
if (!is_array($data)) {
|
||||||
|
throw new WrongUsageException("Invalid JSON format in artifact config file: {$file}");
|
||||||
|
}
|
||||||
|
if (is_array($data)) {
|
||||||
|
ConfigCache::set($content, $data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ConfigValidator::validateAndLintArtifacts(basename($file), $data);
|
ConfigValidator::validateAndLintArtifacts(basename($file), $data);
|
||||||
foreach ($data as $artifact_name => $config) {
|
foreach ($data as $artifact_name => $config) {
|
||||||
@@ -68,6 +77,16 @@ class ArtifactConfig
|
|||||||
return self::$artifact_configs;
|
return self::$artifact_configs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore artifact configs from cache without re-parsing YAML files.
|
||||||
|
*
|
||||||
|
* @internal used by Registry cache layer only
|
||||||
|
*/
|
||||||
|
public static function _restoreFromCache(array $configs): void
|
||||||
|
{
|
||||||
|
self::$artifact_configs = array_merge(self::$artifact_configs, $configs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the configuration for a specific artifact by name.
|
* Get the configuration for a specific artifact by name.
|
||||||
*
|
*
|
||||||
|
|||||||
67
src/StaticPHP/Config/ConfigCache.php
Normal file
67
src/StaticPHP/Config/ConfigCache.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StaticPHP\Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple parse-result cache for YAML/JSON config files.
|
||||||
|
*
|
||||||
|
* Key = raw file content string (files are small, direct comparison is fine).
|
||||||
|
* Value = parsed PHP array.
|
||||||
|
*
|
||||||
|
* Storage: <cwd>/.spc.cache.php (plain PHP, var_export'd array).
|
||||||
|
* Written once on shutdown when any new entry was added.
|
||||||
|
*/
|
||||||
|
class ConfigCache
|
||||||
|
{
|
||||||
|
private static ?array $cache = null;
|
||||||
|
|
||||||
|
private static bool $dirty = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the cached parsed result for $content, or null on miss.
|
||||||
|
*/
|
||||||
|
public static function get(string $content): ?array
|
||||||
|
{
|
||||||
|
self::load();
|
||||||
|
return self::$cache[$content] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a parsed result. Will be persisted to disk on shutdown.
|
||||||
|
*/
|
||||||
|
public static function set(string $content, array $data): void
|
||||||
|
{
|
||||||
|
self::load();
|
||||||
|
self::$cache[$content] = $data;
|
||||||
|
self::$dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write cache to disk if anything changed. Called automatically on shutdown.
|
||||||
|
*/
|
||||||
|
public static function flush(): void
|
||||||
|
{
|
||||||
|
if (!self::$dirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file_put_contents(self::cachePath(), '<?php return ' . var_export(self::$cache, true) . ";\n");
|
||||||
|
self::$dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function cachePath(): string
|
||||||
|
{
|
||||||
|
return getcwd() . '/.spc.cache.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function load(): void
|
||||||
|
{
|
||||||
|
if (self::$cache !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$path = self::cachePath();
|
||||||
|
self::$cache = file_exists($path) ? (require $path) : [];
|
||||||
|
register_shutdown_function([self::class, 'flush']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,12 +50,20 @@ class PackageConfig
|
|||||||
if ($content === false) {
|
if ($content === false) {
|
||||||
throw new WrongUsageException("Failed to read package config file: {$file}");
|
throw new WrongUsageException("Failed to read package config file: {$file}");
|
||||||
}
|
}
|
||||||
// judge extension
|
// judge extension — use cache to skip redundant parsing
|
||||||
$data = match (pathinfo($file, PATHINFO_EXTENSION)) {
|
$data = ConfigCache::get($content);
|
||||||
'json' => json_decode($content, true),
|
if ($data !== null) {
|
||||||
'yml', 'yaml' => Yaml::parse($content),
|
logger()->debug("Config cache hit: {$file}");
|
||||||
default => throw new WrongUsageException("Unsupported package config file format: {$file}"),
|
} else {
|
||||||
};
|
$data = match (pathinfo($file, PATHINFO_EXTENSION)) {
|
||||||
|
'json' => json_decode($content, true),
|
||||||
|
'yml', 'yaml' => extension_loaded('yaml') ? yaml_parse($content) : Yaml::parse($content),
|
||||||
|
default => throw new WrongUsageException("Unsupported package config file format: {$file}"),
|
||||||
|
};
|
||||||
|
if (is_array($data)) {
|
||||||
|
ConfigCache::set($content, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
ConfigValidator::validateAndLintPackages(basename($file), $data);
|
ConfigValidator::validateAndLintPackages(basename($file), $data);
|
||||||
foreach ($data as $pkg_name => $config) {
|
foreach ($data as $pkg_name => $config) {
|
||||||
self::$package_configs[$pkg_name] = $config;
|
self::$package_configs[$pkg_name] = $config;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class Registry
|
|||||||
}
|
}
|
||||||
$data = match (pathinfo($registry_file, PATHINFO_EXTENSION)) {
|
$data = match (pathinfo($registry_file, PATHINFO_EXTENSION)) {
|
||||||
'json' => json_decode($yaml, true),
|
'json' => json_decode($yaml, true),
|
||||||
'yaml', 'yml' => Yaml::parse($yaml),
|
'yaml', 'yml' => extension_loaded('yaml') ? yaml_parse($yaml) : Yaml::parse($yaml),
|
||||||
default => throw new RegistryException("Unsupported registry file format: {$registry_file}"),
|
default => throw new RegistryException("Unsupported registry file format: {$registry_file}"),
|
||||||
};
|
};
|
||||||
if (!is_array($data)) {
|
if (!is_array($data)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user