Просмотр файла vendor/php-di/php-di/src/Definition/ObjectDefinition.php

Размер файла: 6.54Kb
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace DI\Definition;
  6.  
  7. use DI\Definition\Dumper\ObjectDefinitionDumper;
  8. use DI\Definition\ObjectDefinition\MethodInjection;
  9. use DI\Definition\ObjectDefinition\PropertyInjection;
  10. use DI\Definition\Source\DefinitionArray;
  11. use ReflectionClass;
  12.  
  13. /**
  14. * Defines how an object can be instantiated.
  15. *
  16. * @author Matthieu Napoli <matthieu@mnapoli.fr>
  17. */
  18. class ObjectDefinition implements Definition
  19. {
  20. /**
  21. * Entry name (most of the time, same as $classname).
  22. * @var string
  23. */
  24. private $name;
  25.  
  26. /**
  27. * Class name (if null, then the class name is $name).
  28. * @var string|null
  29. */
  30. protected $className;
  31.  
  32. /**
  33. * Constructor parameter injection.
  34. * @var MethodInjection|null
  35. */
  36. protected $constructorInjection;
  37.  
  38. /**
  39. * Property injections.
  40. * @var PropertyInjection[]
  41. */
  42. protected $propertyInjections = [];
  43.  
  44. /**
  45. * Method calls.
  46. * @var MethodInjection[][]
  47. */
  48. protected $methodInjections = [];
  49.  
  50. /**
  51. * @var bool|null
  52. */
  53. protected $lazy;
  54.  
  55. /**
  56. * Store if the class exists. Storing it (in cache) avoids recomputing this.
  57. *
  58. * @var bool
  59. */
  60. private $classExists;
  61.  
  62. /**
  63. * Store if the class is instantiable. Storing it (in cache) avoids recomputing this.
  64. *
  65. * @var bool
  66. */
  67. private $isInstantiable;
  68.  
  69. /**
  70. * @param string $name Entry name
  71. */
  72. public function __construct(string $name, string $className = null)
  73. {
  74. $this->name = $name;
  75. $this->setClassName($className);
  76. }
  77.  
  78. public function getName() : string
  79. {
  80. return $this->name;
  81. }
  82.  
  83. public function setName(string $name)
  84. {
  85. $this->name = $name;
  86. }
  87.  
  88. public function setClassName(string $className = null)
  89. {
  90. $this->className = $className;
  91.  
  92. $this->updateCache();
  93. }
  94.  
  95. public function getClassName() : string
  96. {
  97. if ($this->className !== null) {
  98. return $this->className;
  99. }
  100.  
  101. return $this->name;
  102. }
  103.  
  104. /**
  105. * @return MethodInjection|null
  106. */
  107. public function getConstructorInjection()
  108. {
  109. return $this->constructorInjection;
  110. }
  111.  
  112. public function setConstructorInjection(MethodInjection $constructorInjection)
  113. {
  114. $this->constructorInjection = $constructorInjection;
  115. }
  116.  
  117. public function completeConstructorInjection(MethodInjection $injection)
  118. {
  119. if ($this->constructorInjection !== null) {
  120. // Merge
  121. $this->constructorInjection->merge($injection);
  122. } else {
  123. // Set
  124. $this->constructorInjection = $injection;
  125. }
  126. }
  127.  
  128. /**
  129. * @return PropertyInjection[] Property injections
  130. */
  131. public function getPropertyInjections() : array
  132. {
  133. return $this->propertyInjections;
  134. }
  135.  
  136. public function addPropertyInjection(PropertyInjection $propertyInjection)
  137. {
  138. $className = $propertyInjection->getClassName();
  139. if ($className) {
  140. // Index with the class name to avoid collisions between parent and
  141. // child private properties with the same name
  142. $key = $className . '::' . $propertyInjection->getPropertyName();
  143. } else {
  144. $key = $propertyInjection->getPropertyName();
  145. }
  146.  
  147. $this->propertyInjections[$key] = $propertyInjection;
  148. }
  149.  
  150. /**
  151. * @return MethodInjection[] Method injections
  152. */
  153. public function getMethodInjections() : array
  154. {
  155. // Return array leafs
  156. $injections = [];
  157. array_walk_recursive($this->methodInjections, function ($injection) use (&$injections) {
  158. $injections[] = $injection;
  159. });
  160.  
  161. return $injections;
  162. }
  163.  
  164. public function addMethodInjection(MethodInjection $methodInjection)
  165. {
  166. $method = $methodInjection->getMethodName();
  167. if (! isset($this->methodInjections[$method])) {
  168. $this->methodInjections[$method] = [];
  169. }
  170. $this->methodInjections[$method][] = $methodInjection;
  171. }
  172.  
  173. public function completeFirstMethodInjection(MethodInjection $injection)
  174. {
  175. $method = $injection->getMethodName();
  176.  
  177. if (isset($this->methodInjections[$method][0])) {
  178. // Merge
  179. $this->methodInjections[$method][0]->merge($injection);
  180. } else {
  181. // Set
  182. $this->addMethodInjection($injection);
  183. }
  184. }
  185.  
  186. public function setLazy(bool $lazy = null)
  187. {
  188. $this->lazy = $lazy;
  189. }
  190.  
  191. public function isLazy() : bool
  192. {
  193. if ($this->lazy !== null) {
  194. return $this->lazy;
  195. }
  196. // Default value
  197. return false;
  198. }
  199.  
  200. public function classExists() : bool
  201. {
  202. return $this->classExists;
  203. }
  204.  
  205. public function isInstantiable() : bool
  206. {
  207. return $this->isInstantiable;
  208. }
  209.  
  210. public function replaceNestedDefinitions(callable $replacer)
  211. {
  212. array_walk($this->propertyInjections, function (PropertyInjection $propertyInjection) use ($replacer) {
  213. $propertyInjection->replaceNestedDefinition($replacer);
  214. });
  215.  
  216. if ($this->constructorInjection) {
  217. $this->constructorInjection->replaceNestedDefinitions($replacer);
  218. }
  219.  
  220. array_walk($this->methodInjections, function ($injectionArray) use ($replacer) {
  221. array_walk($injectionArray, function (MethodInjection $methodInjection) use ($replacer) {
  222. $methodInjection->replaceNestedDefinitions($replacer);
  223. });
  224. });
  225. }
  226.  
  227. /**
  228. * Replaces all the wildcards in the string with the given replacements.
  229. *
  230. * @param string[] $replacements
  231. */
  232. public function replaceWildcards(array $replacements)
  233. {
  234. $className = $this->getClassName();
  235.  
  236. foreach ($replacements as $replacement) {
  237. $pos = strpos($className, DefinitionArray::WILDCARD);
  238. if ($pos !== false) {
  239. $className = substr_replace($className, $replacement, $pos, 1);
  240. }
  241. }
  242.  
  243. $this->setClassName($className);
  244. }
  245.  
  246. public function __toString()
  247. {
  248. return (new ObjectDefinitionDumper)->dump($this);
  249. }
  250.  
  251. private function updateCache()
  252. {
  253. $className = $this->getClassName();
  254.  
  255. $this->classExists = class_exists($className) || interface_exists($className);
  256.  
  257. if (! $this->classExists) {
  258. $this->isInstantiable = false;
  259.  
  260. return;
  261. }
  262.  
  263. $class = new ReflectionClass($className);
  264. $this->isInstantiable = $class->isInstantiable();
  265. }
  266. }