Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

155 řádky
4.0KB

  1. <?php
  2. declare(strict_types=1);
  3. namespace Core;
  4. use Exception;
  5. use ReflectionClass;
  6. use ReflectionFunction;
  7. use ReflectionFunctionAbstract;
  8. use ReflectionMethod;
  9. class App
  10. {
  11. protected array $bindings = [];
  12. protected array $instances = [];
  13. public function bind(string $name, mixed $value): void
  14. {
  15. $this->bindings[$name] = $value;
  16. }
  17. public function instance(string $name, mixed $value): void
  18. {
  19. $this->instances[$name] = $value;
  20. }
  21. public function make(string $className): object
  22. {
  23. if (isset($this->bindings[$className])) {
  24. $binding = $this->bindings[$className];
  25. if (is_string($binding) && is_a($binding, $className, true)) {
  26. return $this->instantiate($binding);
  27. }
  28. return $binding;
  29. }
  30. if (isset($this->instances[$className])) {
  31. return $this->instances[$className];
  32. }
  33. return $this->instantiate($className);
  34. }
  35. public function clear(): void
  36. {
  37. $this->bindings = [];
  38. $this->instances = [];
  39. }
  40. public function get(string $name): mixed
  41. {
  42. return $this->instances[$name] ?? $this->bindings[$name] ?? null;
  43. }
  44. public function call(callable|array|string $handler, array $parameters = []): mixed
  45. {
  46. if (is_array($handler)) {
  47. return $this->callMethod($handler, $parameters);
  48. }
  49. if (is_callable($handler)) {
  50. return $this->callFunction($handler, $parameters);
  51. }
  52. throw new Exception('Invalid handler.');
  53. }
  54. protected function callFunction(callable $handler, array $parameters): mixed
  55. {
  56. $reflection = new ReflectionFunction($handler);
  57. return $reflection->invokeArgs($this->resolveArgs($reflection, $parameters));
  58. }
  59. protected function callMethod(array $handler, array $parameters): mixed
  60. {
  61. [$class, $method] = $handler;
  62. if (is_string($class)) {
  63. $class = new $class();
  64. }
  65. $reflection = new ReflectionMethod($class, $method);
  66. return $reflection->invokeArgs($class, $this->resolveArgs($reflection, $parameters));
  67. }
  68. protected function resolveArgs(\ReflectionFunctionAbstract $reflection, array $parameters): array
  69. {
  70. $args = [];
  71. foreach ($reflection->getParameters() as $param) {
  72. $name = $param->getName();
  73. if (array_key_exists($name, $parameters)) {
  74. $args[] = $parameters[$name];
  75. continue;
  76. }
  77. $type = $param->getType();
  78. if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
  79. $typeName = $type->getName();
  80. if (array_key_exists($typeName, $this->instances)) {
  81. $args[] = $this->instances[$typeName];
  82. continue;
  83. }
  84. if (array_key_exists($typeName, $this->bindings)) {
  85. $binding = $this->bindings[$typeName];
  86. if (is_string($binding) && is_a($binding, $typeName, true)) {
  87. $args[] = $this->instantiate($binding);
  88. continue;
  89. }
  90. $args[] = $binding;
  91. continue;
  92. }
  93. }
  94. $args[] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
  95. }
  96. return $args;
  97. }
  98. /**
  99. * @param class-string $className
  100. */
  101. protected function instantiate(string $className): object
  102. {
  103. $reflection = new ReflectionClass($className);
  104. if (!$reflection->isInstantiable()) {
  105. throw new Exception("Cannot instantiate {$className}: class is not instantiable.");
  106. }
  107. $constructor = $reflection->getConstructor();
  108. if ($constructor === null) {
  109. return new $className();
  110. }
  111. $args = $this->resolveArgs($constructor, []);
  112. return $reflection->newInstanceArgs($args);
  113. }
  114. }

Powered by TurnKey Linux.