1515
1616final class Container implements ContainerInterface
1717{
18- /** @var array<class-string, class-string|callable(ContainerInterface $container): object> */
18+ /**
19+ * @var array<class-string, array{
20+ * concrete: object|class-string|callable(ContainerInterface $container): object,
21+ * isSingleton: bool
22+ * }>
23+ */
1924 private array $ entries = [];
2025
2126 /**
2227 * @template T of object
2328 * @param class-string<T> $id
2429 * @return T
2530 * @throws NotFoundExceptionInterface
31+ * @throws ContainerExceptionInterface
2632 */
2733 public function get (string $ id ): object
2834 {
2935 if ($ this ->has ($ id )) {
30- $ entry = $ this ->entries [$ id ];
36+ [
37+ 'concrete ' => $ concrete ,
38+ 'isSingleton ' => $ isSingleton
39+ ] = $ this ->entries [$ id ];
3140
32- if (is_callable ($ entry )) {
41+ if (is_callable ($ concrete )) {
3342 /** @var T */
34- $ concrete = $ entry ($ this );
43+ $ object = $ concrete ($ this );
3544
36- return $ concrete ;
45+ if ($ isSingleton ) {
46+ $ this ->singleton ($ id , $ object );
47+ }
48+
49+ return $ object ;
50+ }
51+
52+ if (is_string ($ concrete )) {
53+ /** @var T */
54+ $ object = $ this ->resolve ($ concrete );
55+
56+ $ this ->singleton ($ id , $ object );
57+
58+ return $ object ;
3759 }
3860
39- $ id = $ entry ;
61+ if (is_object ($ concrete ) && $ isSingleton ) {
62+ return $ concrete ;
63+ }
4064 }
4165
4266 /** @var T */
43- $ object = $ this ->resolve ($ id );
67+ $ object = $ this ->resolve ($ concrete ?? $ id );
4468
4569 return $ object ;
4670 }
@@ -56,9 +80,27 @@ public function has(string $id): bool
5680 * @param class-string<T> $id
5781 * @param class-string<T>|callable(ContainerInterface $container): T $concrete
5882 */
59- public function set (string $ id , $ concrete ): void
83+ public function set (string $ id , $ concrete ): self
6084 {
61- $ this ->entries [$ id ] = $ concrete ;
85+ $ this ->entries [$ id ]['concrete ' ] = $ concrete ;
86+ $ this ->entries [$ id ]['isSingleton ' ] = false ;
87+
88+ return $ this ;
89+ }
90+
91+ /**
92+ * @template T of object
93+ * @param class-string<T>|T $id
94+ */
95+ public function singleton ($ id ): self
96+ {
97+ $ fqcn = is_object ($ id ) ? get_class ($ id ) : $ id ;
98+ $ concrete = func_num_args () === 2 ? func_get_arg (1 ) : $ id ;
99+
100+ $ this ->entries [$ fqcn ]['concrete ' ] = $ concrete ;
101+ $ this ->entries [$ fqcn ]['isSingleton ' ] = true ;
102+
103+ return $ this ;
62104 }
63105
64106 /**
0 commit comments