phabel/src/PluginCache.php

176 lines
5.6 KiB
PHP

<?php
namespace Phabel;
use ReflectionMethod;
/**
* Caches plugin information.
*
* @author Daniil Gentili <daniil@daniil.it>
* @license MIT
*/
class PluginCache
{
/**
* Enter method names for each plugin.
*
* @var array<class-string<PluginInterface>, string[]>
*/
private static array $enterMethods = [];
/**
* Leave method names.
*
* @var array<class-string<PluginInterface>, string[]>
*/
private static array $leaveMethods = [];
/**
* Cache method information.
*
* @param class-string<PluginInterface> $plugin Plugin
*
* @return void
*/
private static function cacheMethods(string $plugin): void
{
if (!isset(self::$enterMethods[$plugin])) {
self::$enterMethods[$plugin] = [];
self::$leaveMethods[$plugin] = [];
foreach (\get_class_methods($plugin) as $method) {
if (\str_starts_with($method, 'enter')) {
$reflection = new ReflectionMethod($plugin, $method);
$type = $reflection->getParameters()[0]->getType()->getName();
self::$enterMethods[$plugin][$type] []= $method;
} elseif (\str_starts_with($method, 'leave')) {
$reflection = new ReflectionMethod($plugin, $method);
$type = $reflection->getParameters()[0]->getType()->getName();
self::$leaveMethods[$plugin][$type] []= $method;
}
}
}
}
/**
* Return whether this plugin can be required by another plugin.
*
* If false, this plugin should only be extended by other plugins, to reduce complexity.
*
* @param class-string<PluginInterface> $plugin Plugin
*
* @return boolean
*/
public static function canBeRequired(string $plugin): bool
{
self::cacheMethods($plugin);
return empty(self::$leaveMethods[$plugin]);
}
/**
* Get enter methods array.
*
* @param class-string<PluginInterface> $plugin Plugin name
*
* @return array<string, string[]>
*/
public static function enterMethods(string $plugin): array
{
self::cacheMethods($plugin);
return self::$enterMethods[$plugin];
}
/**
* Get leave methods array.
*
* @param class-string<PluginInterface> $plugin Plugin name
*
* @return array<string, string[]>
*/
public static function leaveMethods(string $plugin): array
{
self::cacheMethods($plugin);
return self::$leaveMethods[$plugin];
}
/**
* Get runBefore requirements.
*
* @param class-string<PluginInterface> $plugin Plugin
* @param array $config Config
*
* @return array<string, array>
* @psalm-return array<class-string<PluginInterface>, array>
*/
public static function runBefore(string $plugin, array $config): array
{
/** @var array<class-string<PluginInterface>, array<class-string<PluginInterface>, array>> */
static $cache = [];
if (isset($cache[$plugin])) {
return $cache[$plugin];
}
return $cache[$plugin] = self::simplify($plugin::runBefore($config));
}
/**
* Get runAfter requirements.
*
* @param class-string<PluginInterface> $plugin Plugin
* @param array $config Config
*
* @return array<string, array>
* @psalm-return array<class-string<PluginInterface>, array>
*/
public static function runAfter(string $plugin, array $config): array
{
/** @var array<class-string<PluginInterface>, array<class-string<PluginInterface>, array>> */
static $cache = [];
if (isset($cache[$plugin])) {
return $cache[$plugin];
}
return $cache[$plugin] = self::simplify($plugin::runAfter($config));
}
/**
* Get runWithBefore requirements.
*
* @param class-string<PluginInterface> $plugin Plugin
* @param array $config Config
*
* @return array<string, array>
* @psalm-return array<class-string<PluginInterface>, array>
*/
public static function runWithBefore(string $plugin, array $config): array
{
/** @var array<class-string<PluginInterface>, array<class-string<PluginInterface>, array>> */
static $cache = [];
if (isset($cache[$plugin])) {
return $cache[$plugin];
}
return $cache[$plugin] = self::simplify($plugin::runWithBefore($config));
}
/**
* Get runWithAfter requirements.
*
* @param class-string<PluginInterface> $plugin Plugin
* @param array $config Config
*
* @return array<string, array>
* @psalm-return array<class-string<PluginInterface>, array>
*/
public static function runWithAfter(string $plugin, array $config): array
{
/** @var array<class-string<PluginInterface>, array<class-string<PluginInterface>, array>> */
static $cache = [];
if (isset($cache[$plugin])) {
return $cache[$plugin];
}
return $cache[$plugin] = self::simplify($plugin::runWithAfter($config));
}
/**
* Simplify requirements.
*
* @param (array<class-string<PluginInterface>, array>|class-string<PluginInterface>[]) $requirements Requirements
*
* @return array<string, array>
* @psalm-return array<class-string<PluginInterface>, array>
*/
private static function simplify(array $requirements): array
{
return isset($requirements[0]) ? \array_fill_keys($requirements, []) : $requirements;
}
}