66
77use ArrayObject ;
88use Closure ;
9- use InvalidArgumentException ;
109use Psr \Container \ContainerInterface ;
1110use ReflectionClass ;
1211use ReflectionException ;
1817use function assert ;
1918use function call_user_func ;
2019use function class_exists ;
21- use function constant ;
22- use function count ;
23- use function current ;
24- use function defined ;
25- use function explode ;
26- use function file_exists ;
2720use function func_get_args ;
2821use function is_array ;
2922use function is_callable ;
30- use function is_object ;
3123use function is_string ;
32- use function parse_ini_file ;
33- use function parse_ini_string ;
34- use function preg_match ;
35- use function preg_replace ;
36- use function preg_replace_callback ;
37- use function str_contains ;
38- use function trim ;
3924
4025/** @extends ArrayObject<string, mixed> */
4126class Container extends ArrayObject implements ContainerInterface
4227{
43- public function __construct (protected mixed $ configurator = null )
28+ /** @param array<string, mixed> $definitions */
29+ public function __construct (array $ definitions = [])
4430 {
31+ foreach ($ definitions as $ key => $ value ) {
32+ $ this ->offsetSet ((string ) $ key , $ value );
33+ }
4534 }
4635
4736 public function has (string $ id ): bool
4837 {
49- if ($ this ->configurator ) {
50- $ this ->configure ();
51- }
52-
5338 if (!parent ::offsetExists ($ id )) {
5439 return false ;
5540 }
@@ -64,10 +49,6 @@ public function has(string $id): bool
6449
6550 public function getItem (string $ name , bool $ raw = false ): mixed
6651 {
67- if ($ this ->configurator ) {
68- $ this ->configure ();
69- }
70-
7152 if (!isset ($ this [$ name ])) {
7253 throw new NotFoundException ('Item ' . $ name . ' not found ' );
7354 }
@@ -88,44 +69,6 @@ public function get(string $id): mixed
8869 return $ this ->getItem ($ id );
8970 }
9071
91- public function loadString (string $ configurator ): void
92- {
93- $ iniData = parse_ini_string ($ configurator , true );
94- if ($ iniData === false || count ($ iniData ) === 0 ) {
95- throw new InvalidArgumentException ('Invalid configuration string ' );
96- }
97-
98- $ this ->loadArray ($ iniData );
99- }
100-
101- public function loadFile (string $ configurator ): void
102- {
103- $ iniData = parse_ini_file ($ configurator , true );
104- if ($ iniData === false ) {
105- throw new InvalidArgumentException ('Invalid configuration INI file ' );
106- }
107-
108- $ this ->loadArray ($ iniData );
109- }
110-
111- /** @param array<string, mixed> $configurator */
112- public function loadArray (array $ configurator ): void
113- {
114- foreach ($ this ->state () + $ configurator as $ key => $ value ) {
115- if ($ value instanceof Closure) {
116- $ this ->offsetSet ((string ) $ key , $ value );
117- continue ;
118- }
119-
120- if ($ value instanceof Instantiator) {
121- $ this ->offsetSet ((string ) $ key , $ value );
122- continue ;
123- }
124-
125- $ this ->parseItem ($ key , $ value );
126- }
127- }
128-
12972 public function offsetSet (mixed $ key , mixed $ value ): void
13073 {
13174 if ($ value instanceof Autowire) {
@@ -140,235 +83,6 @@ public function set(string $name, mixed $value): void
14083 $ this [$ name ] = $ value ;
14184 }
14285
143- protected function configure (): void
144- {
145- $ configurator = $ this ->configurator ;
146- $ this ->configurator = null ;
147-
148- if ($ configurator === null ) {
149- return ;
150- }
151-
152- if (is_array ($ configurator )) {
153- $ this ->loadArray ($ configurator );
154-
155- return ;
156- }
157-
158- if (is_string ($ configurator ) && file_exists ($ configurator )) {
159- $ this ->loadFile ($ configurator );
160-
161- return ;
162- }
163-
164- if (is_string ($ configurator )) {
165- $ this ->loadString ($ configurator );
166-
167- return ;
168- }
169-
170- throw new InvalidArgumentException ('Invalid input. Must be a valid file or array ' );
171- }
172-
173- /** @return array<string, mixed> */
174- protected function state (): array
175- {
176- return array_filter (
177- $ this ->getArrayCopy (),
178- static fn ($ v ): bool => !is_object ($ v ) || !$ v instanceof Instantiator,
179- );
180- }
181-
182- protected function keyHasStateInstance (string $ key , mixed &$ k ): bool
183- {
184- return $ this ->offsetExists ($ k = current (explode (' ' , $ key )));
185- }
186-
187- protected function keyHasInstantiator (string $ key ): bool
188- {
189- return str_contains ($ key , ' ' );
190- }
191-
192- protected function parseItem (string |int $ key , mixed $ value ): void
193- {
194- $ key = trim ((string ) $ key );
195- if ($ this ->keyHasInstantiator ($ key )) {
196- if ($ this ->keyHasStateInstance ($ key , $ k )) {
197- $ this ->offsetSet ($ key , $ this [$ k ]);
198- } else {
199- $ this ->parseInstantiator ($ key , $ value );
200- }
201- } else {
202- $ this ->parseStandardItem ($ key , $ value );
203- }
204- }
205-
206- /**
207- * @param array<mixed> $value
208- *
209- * @return array<mixed>
210- */
211- protected function parseSubValues (array &$ value ): array
212- {
213- foreach ($ value as &$ subValue ) {
214- $ subValue = $ this ->parseValue ($ subValue );
215- }
216-
217- return $ value ;
218- }
219-
220- protected function parseStandardItem (string $ key , mixed &$ value ): void
221- {
222- if (is_array ($ value )) {
223- $ this ->parseSubValues ($ value );
224- } else {
225- $ value = $ this ->parseValue ($ value );
226- }
227-
228- $ this ->offsetSet ($ key , $ value );
229- }
230-
231- protected function removeDuplicatedSpaces (string $ string ): string
232- {
233- return (string ) preg_replace ('/\s+/ ' , ' ' , $ string );
234- }
235-
236- protected function parseInstantiator (string $ key , mixed $ value ): void
237- {
238- $ key = $ this ->removeDuplicatedSpaces ($ key );
239- [$ keyName , $ keyClass ] = explode (' ' , $ key , 2 );
240- if ($ keyName === 'instanceof ' ) {
241- $ keyName = $ keyClass ;
242- }
243-
244- /** @var class-string $keyClass */
245- $ instantiator = $ this ->createInstantiator ($ keyClass );
246-
247- if (is_array ($ value )) {
248- foreach ($ value as $ property => $ pValue ) {
249- $ instantiator ->setParam ($ property , $ this ->parseValue ($ pValue ));
250- }
251- } else {
252- $ instantiator ->setParam ('__construct ' , $ this ->parseValue ($ value ));
253- }
254-
255- $ this ->offsetSet ($ keyName , $ instantiator );
256- }
257-
258- /** @param class-string $keyClass */
259- protected function createInstantiator (string $ keyClass ): Instantiator
260- {
261- if (!str_contains ($ keyClass , ' ' )) {
262- return new Instantiator ($ keyClass );
263- }
264-
265- [$ modifier , $ className ] = explode (' ' , $ keyClass , 2 );
266-
267- /** @var class-string $className */
268- return match ($ modifier ) {
269- 'new ' => new Factory ($ className ),
270- 'autowire ' => new Autowire ($ className ),
271- default => new Instantiator ($ keyClass ),
272- };
273- }
274-
275- protected function parseValue (mixed $ value ): mixed
276- {
277- if ($ value instanceof Instantiator) {
278- return $ value ;
279- }
280-
281- if (is_array ($ value )) {
282- return $ this ->parseSubValues ($ value );
283- }
284-
285- if (empty ($ value )) {
286- return null ;
287- }
288-
289- if (!is_string ($ value )) {
290- return $ value ;
291- }
292-
293- return $ this ->parseSingleValue ($ value );
294- }
295-
296- protected function hasCompleteBrackets (string $ value ): bool
297- {
298- return str_contains ($ value , '[ ' ) && str_contains ($ value , '] ' );
299- }
300-
301- protected function parseSingleValue (string $ value ): mixed
302- {
303- $ value = trim ($ value );
304- if ($ this ->hasCompleteBrackets ($ value )) {
305- return $ this ->parseBrackets ($ value );
306- }
307-
308- return $ this ->parseConstants ($ value );
309- }
310-
311- protected function parseConstants (string $ value ): mixed
312- {
313- if (preg_match ('/^[ \\\\a-zA-Z_]+([:]{2}[A-Z_]+)?$/ ' , $ value ) && defined ($ value )) {
314- return constant ($ value );
315- }
316-
317- return $ value ;
318- }
319-
320- protected function matchSequence (string &$ value ): bool
321- {
322- if (preg_match ('/^\[(.*?,.*?)\]$/ ' , $ value , $ match )) {
323- $ value = $ match [1 ];
324-
325- return true ;
326- }
327-
328- return false ;
329- }
330-
331- protected function matchReference (string &$ value ): bool
332- {
333- if (preg_match ('/^\[([[:alnum:]_ \\\\]+)\]$/ ' , $ value , $ match )) {
334- $ value = $ match [1 ];
335-
336- return true ;
337- }
338-
339- return false ;
340- }
341-
342- protected function parseBrackets (string $ value ): mixed
343- {
344- if ($ this ->matchSequence ($ value )) {
345- return $ this ->parseArgumentList ($ value );
346- }
347-
348- if ($ this ->matchReference ($ value )) {
349- return $ this ->getItem ($ value , true );
350- }
351-
352- return $ this ->parseVariables ($ value );
353- }
354-
355- protected function parseVariables (string $ value ): string
356- {
357- return (string ) preg_replace_callback (
358- '/\[(\w+)\]/ ' ,
359- fn (array $ match ): string => $ this [$ match [1 ]] ?: '' ,
360- $ value ,
361- );
362- }
363-
364- /** @return array<mixed> */
365- protected function parseArgumentList (string $ value ): array
366- {
367- $ subValues = explode (', ' , $ value );
368-
369- return $ this ->parseSubValues ($ subValues );
370- }
371-
37286 protected function lazyLoad (string $ name ): mixed
37387 {
37488 $ callback = $ this [$ name ];
@@ -431,10 +145,6 @@ static function ($param) use ($container) {
431145 parent ::offsetSet ($ name , $ item );
432146 }
433147
434- if ($ this ->configurator ) {
435- $ this ->configure ();
436- }
437-
438148 return $ this ;
439149 }
440150
0 commit comments