PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/firebase/vendor/nette/di/src/DI/DependencyChecker.php

https://bitbucket.org/devpronitzz/healthcase
PHP | 176 lines | 132 code | 24 blank | 20 comment | 17 complexity | 31e8206f8614d2ecf5d4a117c867e3b2 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, Apache-2.0, MIT
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (https://nette.org)
  4. * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  5. */
  6. namespace Nette\DI;
  7. use Nette;
  8. use Nette\Utils\Reflection;
  9. use ReflectionClass;
  10. use ReflectionMethod;
  11. /**
  12. * Cache dependencies checker.
  13. */
  14. class DependencyChecker
  15. {
  16. use Nette\SmartObject;
  17. const VERSION = 1;
  18. /** @var array of ReflectionClass|\ReflectionFunctionAbstract|string */
  19. private $dependencies = [];
  20. /**
  21. * Adds dependencies to the list.
  22. * @return static
  23. */
  24. public function add(array $deps)
  25. {
  26. $this->dependencies = array_merge($this->dependencies, $deps);
  27. return $this;
  28. }
  29. /**
  30. * Exports dependencies.
  31. * @return array
  32. */
  33. public function export()
  34. {
  35. $files = $phpFiles = $classes = $functions = [];
  36. foreach ($this->dependencies as $dep) {
  37. if (is_string($dep)) {
  38. $files[] = $dep;
  39. } elseif ($dep instanceof ReflectionClass) {
  40. if (empty($classes[$name = $dep->getName()])) {
  41. $all = [$name] + class_parents($name) + class_implements($name);
  42. foreach ($all as &$item) {
  43. $all += class_uses($item);
  44. $phpFiles[] = (new ReflectionClass($item))->getFileName();
  45. $classes[$item] = true;
  46. }
  47. }
  48. } elseif ($dep instanceof \ReflectionFunctionAbstract) {
  49. $phpFiles[] = $dep->getFileName();
  50. $functions[] = Reflection::toString($dep);
  51. } else {
  52. throw new Nette\InvalidStateException('Unexpected dependency ' . gettype($dep));
  53. }
  54. }
  55. $classes = array_keys($classes);
  56. $functions = array_unique($functions, SORT_REGULAR);
  57. $hash = self::calculateHash($classes, $functions);
  58. $files = @array_map('filemtime', array_combine($files, $files)); // @ - file may not exist
  59. $phpFiles = @array_map('filemtime', array_combine($phpFiles, $phpFiles)); // @ - file may not exist
  60. return [self::VERSION, $files, $phpFiles, $classes, $functions, $hash];
  61. }
  62. /**
  63. * Are dependencies expired?
  64. * @return bool
  65. */
  66. public static function isExpired($version, $files, &$phpFiles, $classes, $functions, $hash)
  67. {
  68. $current = @array_map('filemtime', array_combine($tmp = array_keys($files), $tmp)); // @ - files may not exist
  69. $origPhpFiles = $phpFiles;
  70. $phpFiles = @array_map('filemtime', array_combine($tmp = array_keys($phpFiles), $tmp)); // @ - files may not exist
  71. return $version !== self::VERSION
  72. || $files !== $current
  73. || ($phpFiles !== $origPhpFiles && $hash !== self::calculateHash($classes, $functions));
  74. }
  75. private static function calculateHash($classes, $functions)
  76. {
  77. $hash = [];
  78. foreach ($classes as $name) {
  79. try {
  80. $class = new ReflectionClass($name);
  81. } catch (\ReflectionException $e) {
  82. return;
  83. }
  84. $hash[] = [
  85. $name,
  86. Reflection::getUseStatements($class),
  87. $class->isAbstract(),
  88. get_parent_class($name),
  89. class_implements($name),
  90. class_uses($name),
  91. ];
  92. foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
  93. if ($prop->getDeclaringClass() == $class) { // intentionally ==
  94. $hash[] = [$name, $prop->getName(), $prop->getDocComment()];
  95. }
  96. }
  97. foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
  98. if ($method->getDeclaringClass() == $class) { // intentionally ==
  99. $hash[] = [
  100. $name,
  101. $method->getName(),
  102. $method->getDocComment(),
  103. self::hashParameters($method),
  104. PHP_VERSION_ID >= 70000 && $method->hasReturnType()
  105. ? [(string) $method->getReturnType(), $method->getReturnType()->allowsNull()]
  106. : null,
  107. ];
  108. }
  109. }
  110. }
  111. $flip = array_flip($classes);
  112. foreach ($functions as $name) {
  113. try {
  114. $method = strpos($name, '::') ? new ReflectionMethod($name) : new \ReflectionFunction($name);
  115. } catch (\ReflectionException $e) {
  116. return;
  117. }
  118. $class = $method instanceof ReflectionMethod ? $method->getDeclaringClass() : null;
  119. if ($class && isset($flip[$class->getName()])) {
  120. continue;
  121. }
  122. $hash[] = [
  123. $name,
  124. $class ? Reflection::getUseStatements($method->getDeclaringClass()) : null,
  125. $method->getDocComment(),
  126. self::hashParameters($method),
  127. PHP_VERSION_ID >= 70000 && $method->hasReturnType()
  128. ? [(string) $method->getReturnType(), $method->getReturnType()->allowsNull()]
  129. : null,
  130. ];
  131. }
  132. return md5(serialize($hash));
  133. }
  134. private static function hashParameters(\ReflectionFunctionAbstract $method)
  135. {
  136. $res = [];
  137. if (PHP_VERSION_ID < 70000 && $method->getNumberOfParameters() && $method->getFileName()) {
  138. $res[] = file($method->getFileName())[$method->getStartLine() - 1];
  139. }
  140. foreach ($method->getParameters() as $param) {
  141. $res[] = [
  142. $param->getName(),
  143. PHP_VERSION_ID >= 70000 ? [Reflection::getParameterType($param), $param->allowsNull()] : null,
  144. $param->isVariadic(),
  145. $param->isDefaultValueAvailable()
  146. ? [Reflection::getParameterDefaultValue($param)]
  147. : null,
  148. ];
  149. }
  150. return $res;
  151. }
  152. }