From 58e2807e8a5c208d536373e63e04a5ca0d69e0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Klva=C4=8D?= Date: Thu, 9 Aug 2018 22:15:17 +0200 Subject: [PATCH] DependencyChecker: added callback support --- src/DI/DependencyChecker.php | 33 ++++++++++++++++++++++------- tests/DI/Compiler.dependencies.phpt | 30 +++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/DI/DependencyChecker.php b/src/DI/DependencyChecker.php index 3598ed2fb..ad34af28c 100644 --- a/src/DI/DependencyChecker.php +++ b/src/DI/DependencyChecker.php @@ -22,9 +22,9 @@ class DependencyChecker { use Nette\SmartObject; - public const VERSION = 1; + public const VERSION = 2; - /** @var array of ReflectionClass|\ReflectionFunctionAbstract|string */ + /** @var array of ReflectionClass|\ReflectionFunctionAbstract|string|array */ private $dependencies = []; @@ -44,11 +44,14 @@ public function add(array $deps) */ public function export(): array { - $files = $phpFiles = $classes = $functions = []; + $files = $phpFiles = $classes = $functions = $callbacks = []; foreach ($this->dependencies as $dep) { if (is_string($dep)) { $files[] = $dep; + } elseif (is_array($dep) && isset($dep[0]) && Nette\Utils\Callback::isStatic($dep[0])) { + $callbacks[] = $dep; + } elseif ($dep instanceof ReflectionClass) { if (empty($classes[$name = $dep->getName()])) { $all = [$name] + class_parents($name) + class_implements($name); @@ -70,28 +73,30 @@ public function export(): array $classes = array_keys($classes); $functions = array_unique($functions, SORT_REGULAR); - $hash = self::calculateHash($classes, $functions); + $reflectionHash = self::calculateReflectionHash($classes, $functions); + $callbackHash = self::calculateCallbackHash($callbacks); $files = @array_map('filemtime', array_combine($files, $files)); // @ - file may not exist $phpFiles = @array_map('filemtime', array_combine($phpFiles, $phpFiles)); // @ - file may not exist - return [self::VERSION, $files, $phpFiles, $classes, $functions, $hash]; + return [self::VERSION, $files, $phpFiles, $classes, $functions, $reflectionHash, $callbacks, $callbackHash]; } /** * Are dependencies expired? */ - public static function isExpired(int $version, array $files, array &$phpFiles, array $classes, array $functions, string $hash): bool + public static function isExpired(int $version, array $files, array &$phpFiles, array $classes, array $functions, string $reflectionHash, array $callbacks = [], string $callbackHash = ''): bool { $current = @array_map('filemtime', array_combine($tmp = array_keys($files), $tmp)); // @ - files may not exist $origPhpFiles = $phpFiles; $phpFiles = @array_map('filemtime', array_combine($tmp = array_keys($phpFiles), $tmp)); // @ - files may not exist return $version !== self::VERSION || $files !== $current - || ($phpFiles !== $origPhpFiles && $hash !== self::calculateHash($classes, $functions)); + || ($phpFiles !== $origPhpFiles && $reflectionHash !== self::calculateReflectionHash($classes, $functions)) + || $callbackHash !== self::calculateCallbackHash($callbacks); } - private static function calculateHash(array $classes, array $functions): ?string + private static function calculateReflectionHash(array $classes, array $functions): ?string { $hash = []; foreach ($classes as $name) { @@ -155,6 +160,18 @@ class_uses($name), } + private static function calculateCallbackHash(array $callbacks): string + { + $hash = []; + + foreach ($callbacks as $callback) { + $hash[] = [$callback, call_user_func(...$callback)]; + } + + return md5(serialize($hash)); + } + + private static function hashParameters(\ReflectionFunctionAbstract $method): array { $res = []; diff --git a/tests/DI/Compiler.dependencies.phpt b/tests/DI/Compiler.dependencies.phpt index 68af9dd44..6c0143f4c 100644 --- a/tests/DI/Compiler.dependencies.phpt +++ b/tests/DI/Compiler.dependencies.phpt @@ -16,7 +16,7 @@ require __DIR__ . '/../bootstrap.php'; $compiler = new DI\Compiler; Assert::same( - [DependencyChecker::VERSION, [], [], [], [], '40cd750bba9870f18aada2478b24840a'], + [DependencyChecker::VERSION, [], [], [], [], '40cd750bba9870f18aada2478b24840a', [], '40cd750bba9870f18aada2478b24840a'], $compiler->exportDependencies() ); Assert::false(DependencyChecker::isExpired(...$compiler->exportDependencies())); @@ -24,7 +24,7 @@ Assert::false(DependencyChecker::isExpired(...$compiler->exportDependencies())); $compiler->addDependencies(['file1', __FILE__]); Assert::same( - [DependencyChecker::VERSION, ['file1' => false, __FILE__ => filemtime(__FILE__)], [], [], [], '40cd750bba9870f18aada2478b24840a'], + [DependencyChecker::VERSION, ['file1' => false, __FILE__ => filemtime(__FILE__)], [], [], [], '40cd750bba9870f18aada2478b24840a', [], '40cd750bba9870f18aada2478b24840a'], $compiler->exportDependencies() ); Assert::false(DependencyChecker::isExpired(...$compiler->exportDependencies())); @@ -32,10 +32,34 @@ Assert::false(DependencyChecker::isExpired(...$compiler->exportDependencies())); $compiler->addDependencies(['file1', null, 'file3']); Assert::same( - [DependencyChecker::VERSION, ['file1' => false, __FILE__ => filemtime(__FILE__), 'file3' => false], [], [], [], '40cd750bba9870f18aada2478b24840a'], + [DependencyChecker::VERSION, ['file1' => false, __FILE__ => filemtime(__FILE__), 'file3' => false], [], [], [], '40cd750bba9870f18aada2478b24840a', [], '40cd750bba9870f18aada2478b24840a'], $compiler->exportDependencies() ); $res = $compiler->exportDependencies(); $res[1]['file4'] = 123; Assert::true(DependencyChecker::isExpired(...$res)); + +$compiler = new DI\Compiler; +$compiler->addDependencies([['CustomDependencyChecker::check', 0]]); +$res = $compiler->exportDependencies(); + +Assert::same( + [DependencyChecker::VERSION, [], [], [], [], '40cd750bba9870f18aada2478b24840a', [['CustomDependencyChecker::check', 0]], '75ea70c3b123324ae9c9ccb31bd7a6c0'], + $res +); + +Assert::false(DependencyChecker::isExpired(...$res)); +CustomDependencyChecker::$state++; +Assert::true(DependencyChecker::isExpired(...$res)); + +class CustomDependencyChecker +{ + public static $state = 0; + + + public static function check($state) + { + return self::$state === $state; + } +}