Skip to content

Commit f01aab8

Browse files
committed
Merge branch 'cleanup'
2 parents a805cbf + 332112a commit f01aab8

File tree

8 files changed

+295
-111
lines changed

8 files changed

+295
-111
lines changed

src/Toolkit/Core/AbstractFacade.php

Lines changed: 62 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ abstract class AbstractFacade implements FacadeInterface
2929
/** @use ResolvesServiceLists<TService> */
3030
use ResolvesServiceLists;
3131

32+
/**
33+
* @var array<class-string<static>,TService>
34+
*/
35+
private static array $Instances = [];
36+
37+
/**
38+
* @var array<class-string<static>,int>
39+
*/
40+
private static array $ListenerIds = [];
41+
3242
/**
3343
* Get the facade's underlying class, or an array that maps its underlying
3444
* class to compatible implementations
@@ -40,16 +50,6 @@ abstract class AbstractFacade implements FacadeInterface
4050
*/
4151
abstract protected static function getService();
4252

43-
/**
44-
* @var array<class-string<static>,TService>
45-
*/
46-
private static array $Instances = [];
47-
48-
/**
49-
* @var array<class-string<static>,int>
50-
*/
51-
private static array $ListenerIds = [];
52-
5353
/**
5454
* @inheritDoc
5555
*/
@@ -75,7 +75,7 @@ final public static function load(?object $instance = null): void
7575
*/
7676
final public static function swap(object $instance): void
7777
{
78-
self::unload();
78+
self::doUnload();
7979
self::$Instances[static::class] = self::doLoad($instance);
8080
}
8181

@@ -89,60 +89,17 @@ final public static function unloadAll(): void
8989
if ($class === Event::class) {
9090
continue;
9191
}
92-
$class::unload();
92+
$class::doUnload();
9393
}
94-
Event::unload();
94+
Event::doUnload();
9595
}
9696

9797
/**
9898
* @inheritDoc
9999
*/
100100
final public static function unload(): void
101101
{
102-
// @phpstan-ignore-next-line
103-
if (static::class === Event::class) {
104-
$loaded = array_keys(self::$Instances);
105-
if ($loaded && $loaded !== [Event::class]) {
106-
throw new LogicException(sprintf(
107-
'%s cannot be unloaded before other facades',
108-
Event::class,
109-
));
110-
}
111-
}
112-
113-
$id = self::$ListenerIds[static::class] ?? null;
114-
if ($id !== null) {
115-
Event::removeListener($id);
116-
unset(self::$ListenerIds[static::class]);
117-
}
118-
119-
$instance = self::$Instances[static::class] ?? null;
120-
if (!$instance) {
121-
return;
122-
}
123-
124-
if (static::class !== App::class) {
125-
$container = Container::maybeGetGlobalContainer();
126-
if ($container) {
127-
$serviceName = self::getServiceName();
128-
if (
129-
$container->hasInstance($serviceName) &&
130-
$container->get($serviceName) === $instance
131-
) {
132-
$container->unbind($serviceName);
133-
}
134-
}
135-
}
136-
137-
if ($instance instanceof FacadeAwareInterface) {
138-
$instance = $instance->withoutFacade(static::class, true);
139-
}
140-
141-
if ($instance instanceof Unloadable) {
142-
$instance->unload();
143-
}
144-
145-
unset(self::$Instances[static::class]);
102+
self::doUnload();
146103
}
147104

148105
/**
@@ -293,4 +250,52 @@ private static function createInstance(): object
293250
static::class,
294251
));
295252
}
253+
254+
private static function doUnload(): void
255+
{
256+
// @phpstan-ignore-next-line
257+
if (static::class === Event::class) {
258+
$loaded = array_keys(self::$Instances);
259+
if ($loaded && $loaded !== [Event::class]) {
260+
throw new LogicException(sprintf(
261+
'%s cannot be unloaded before other facades',
262+
Event::class,
263+
));
264+
}
265+
}
266+
267+
$id = self::$ListenerIds[static::class] ?? null;
268+
if ($id !== null) {
269+
Event::removeListener($id);
270+
unset(self::$ListenerIds[static::class]);
271+
}
272+
273+
$instance = self::$Instances[static::class] ?? null;
274+
if (!$instance) {
275+
return;
276+
}
277+
278+
if (static::class !== App::class) {
279+
$container = Container::maybeGetGlobalContainer();
280+
if ($container) {
281+
$serviceName = self::getServiceName();
282+
if (
283+
$container->hasInstance($serviceName) &&
284+
$container->get($serviceName) === $instance
285+
) {
286+
$container->unbindInstance($serviceName);
287+
}
288+
}
289+
}
290+
291+
if ($instance instanceof FacadeAwareInterface) {
292+
$instance = $instance->withoutFacade(static::class, true);
293+
}
294+
295+
if ($instance instanceof Unloadable) {
296+
$instance->unload();
297+
}
298+
299+
unset(self::$Instances[static::class]);
300+
}
296301
}

src/Toolkit/Core/Concern/HasFacade.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ final public function withoutFacade(string $facade, bool $unloading)
8989

9090
// Keep a copy of the cloned instance for future reuse if the facade is
9191
// not being unloaded
92-
if (!$unloading) {
92+
if ($unloading) {
93+
$instance->InstanceWithoutFacade = null;
94+
$instance->InstanceWithFacade = null;
95+
} else {
9396
$instance->InstanceWithoutFacade = $instance;
9497
$instance->InstanceWithFacade = $this;
9598
}

src/Toolkit/Core/Contract/FacadeInterface.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@
77
/**
88
* Provides a static interface to an underlying instance
99
*
10-
* Underlying instances that implement {@see FacadeAwareInterface} are replaced
11-
* with the object returned by {@see FacadeAwareInterface::withFacade()}, and
12-
* its {@see FacadeAwareInterface::withoutFacade()} method is used to service
13-
* the facade's {@see swap()}, {@see unload()} and {@see getInstance()} methods.
14-
*
1510
* @api
1611
*
1712
* @template TService of object
@@ -28,6 +23,10 @@ public static function isLoaded(): bool;
2823
*
2924
* If `$instance` is `null`, the facade creates a new underlying instance.
3025
*
26+
* Then, if the instance implements {@see FacadeAwareInterface}, it is
27+
* replaced with the return value of
28+
* {@see FacadeAwareInterface::withFacade()}.
29+
*
3130
* @param TService|null $instance
3231
* @throws LogicException if the facade's underlying instance is already
3332
* loaded.
@@ -37,12 +36,22 @@ public static function load(?object $instance = null): void;
3736
/**
3837
* Replace the facade's underlying instance
3938
*
39+
* Equivalent to calling {@see unload()} before passing `$instance` to
40+
* {@see load()}.
41+
*
4042
* @param TService $instance
4143
*/
4244
public static function swap(object $instance): void;
4345

4446
/**
4547
* Remove the facade's underlying instance if loaded
48+
*
49+
* If the underlying instance implements {@see FacadeAwareInterface}, it is
50+
* replaced with the return value of
51+
* {@see FacadeAwareInterface::withoutFacade()}.
52+
*
53+
* Then, if the instance implements {@see Unloadable}, its
54+
* {@see Unloadable::unload()} method is called.
4655
*/
4756
public static function unload(): void;
4857

src/Util/Container/Container.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ public function unload(): void
7777
{
7878
if (self::$GlobalContainer === $this) {
7979
self::setGlobalContainer(null);
80-
$this->unloadFacades();
8180
}
8281

83-
unset($this->Dice);
82+
$this->unloadFacades();
83+
84+
$this->Dice = new Dice();
85+
$this->bindContainer();
8486
}
8587

8688
private function bindContainer(): void
@@ -258,6 +260,17 @@ final public function has(string $id): bool
258260
return $this->Dice->hasRule($id) || $this->Dice->hasShared($id);
259261
}
260262

263+
/**
264+
* @inheritDoc
265+
*/
266+
final public function hasSingleton(string $id): bool
267+
{
268+
return $this->Dice->hasShared($id) || (
269+
$this->Dice->hasRule($id) &&
270+
($this->Dice->getRule($id)['shared'] ?? false)
271+
);
272+
}
273+
261274
/**
262275
* @inheritDoc
263276
*/
@@ -647,6 +660,25 @@ final public function unbind(string $id): self
647660
return $this;
648661
}
649662

663+
/**
664+
* @inheritDoc
665+
*/
666+
final public function unbindInstance(string $id): self
667+
{
668+
if (!$this->Dice->hasShared($id)) {
669+
return $this;
670+
}
671+
672+
if ($this->Dice->hasRule($id)) {
673+
// Reapplying the rule removes the instance
674+
$this->Dice = $this->Dice->addRule($id, $this->Dice->getRule($id));
675+
return $this;
676+
}
677+
678+
$this->Dice = $this->Dice->removeRule($id);
679+
return $this;
680+
}
681+
650682
/**
651683
* 0 if another container has the same bindings, otherwise 1
652684
*

0 commit comments

Comments
 (0)