Passed
Push — main ( d71b68...a743f7 )
by Dimitri
08:12 queued 04:09
created

Services   F

Complexity

Total Complexity 125

Size/Duplication

Total Lines 584
Duplicated Lines 0 %

Test Coverage

Coverage 59.29%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 175
c 3
b 0
f 0
dl 0
loc 584
ccs 67
cts 113
cp 0.5929
rs 2
wmc 125

37 Methods

Rating   Name   Duplication   Size   Complexity  
A emitter() 0 7 3
A request() 0 7 3
A timer() 0 7 3
A language() 0 3 1
A toolbar() 0 9 3
A locator() 0 7 3
A logger() 0 7 3
B cookie() 0 14 8
A autoloader() 0 10 3
A routes() 0 7 3
A event() 0 7 3
A response() 0 7 3
A encrypter() 0 11 3
B session() 0 32 7
A router() 0 14 5
A redirection() 0 7 3
A container() 0 7 3
A responsecache() 0 7 3
A config() 0 7 3
A fs() 0 7 3
A storage() 0 7 3
A componentLoader() 0 7 3
A viewer() 0 7 3
A cacheServices() 0 18 5
A __callStatic() 0 7 2
A serviceExists() 0 13 3
A set() 0 4 1
A discoverServices() 0 7 2
A negotiator() 0 16 5
A reset() 0 7 2
A factory() 0 3 1
A injectMock() 0 3 1
B translator() 0 15 7
A mail() 0 17 6
A singleton() 0 10 3
A cache() 0 16 6
A uri() 0 7 3

How to fix   Complexity   

Complex Class

Complex classes like Services often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Services, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Container;
13
14
use BlitzPHP\Autoloader\Autoloader;
15
use BlitzPHP\Autoloader\Locator;
16
use BlitzPHP\Cache\Cache;
17
use BlitzPHP\Cache\ResponseCache;
18
use BlitzPHP\Config\Config;
19
use BlitzPHP\Contracts\Autoloader\LocatorInterface;
20
use BlitzPHP\Contracts\Database\ConnectionResolverInterface;
21
use BlitzPHP\Contracts\Security\EncrypterInterface;
22
use BlitzPHP\Contracts\Session\CookieManagerInterface;
23
use BlitzPHP\Debug\Logger;
24
use BlitzPHP\Debug\Timer;
25
use BlitzPHP\Debug\Toolbar;
26
use BlitzPHP\Event\EventManager;
27
use BlitzPHP\Filesystem\Filesystem;
28
use BlitzPHP\Filesystem\FilesystemManager;
29
use BlitzPHP\Http\Negotiator;
30
use BlitzPHP\Http\Redirection;
31
use BlitzPHP\Http\Request;
32
use BlitzPHP\Http\Response;
33
use BlitzPHP\Http\ResponseEmitter;
34
use BlitzPHP\Http\ServerRequest;
35
use BlitzPHP\Http\ServerRequestFactory;
36
use BlitzPHP\Http\Uri;
37
use BlitzPHP\Http\UrlGenerator;
38
use BlitzPHP\Mail\Mail;
39
use BlitzPHP\Router\RouteCollection;
40
use BlitzPHP\Router\Router;
41
use BlitzPHP\Security\Encryption\Encryption;
42
use BlitzPHP\Session\Cookie\Cookie;
43
use BlitzPHP\Session\Cookie\CookieManager;
44
use BlitzPHP\Session\Handlers\Database as DatabaseSessionHandler;
45
use BlitzPHP\Session\Handlers\Database\MySQL as MySQLSessionHandler;
46
use BlitzPHP\Session\Handlers\Database\Postgre as PostgreSessionHandler;
47
use BlitzPHP\Session\Store;
48
use BlitzPHP\Translator\Translate;
49
use BlitzPHP\Utilities\Helpers;
50
use BlitzPHP\Utilities\String\Text;
51
use BlitzPHP\View\Components\ComponentLoader;
52
use BlitzPHP\View\View;
53
use Psr\Log\LoggerInterface;
54
use stdClass;
55
56
/**
57
 * Service
58
 *
59
 * Les services sont simplement d'autres classes/bibliothèques que le système utilise
60
 * pour faire son travail. Ceci est utilisé par BlitzPHP pour permettre au coeur du
61
 * framework à échanger facilement sans affecter l'utilisation à l'intérieur
62
 * le reste de votre application.
63
 *
64
 * Ceci est utilisé à la place d'un conteneur d'injection de dépendance principalement
65
 * en raison de sa simplicité, qui permet un meilleur entretien à long terme
66
 * des applications construites sur BlitzPHP. Un effet secondaire bonus
67
 * est que les IDE sont capables de déterminer quelle classe vous appelez
68
 * alors qu'avec les conteneurs DI, il n'y a généralement aucun moyen pour eux de le faire.
69
 */
70
class Services
71
{
72
    /**
73
     * Cache des instances des services demander comme instance "partagee".
74
     * La cle est le FQCN du service.
75
     */
76
    protected static array $instances = [];
77
78
    /**
79
     * Objets simulés à tester qui sont renvoyés s'ils existent.
80
     */
81
    protected static array $mocks = [];
82
83
    /**
84
     * Cache d'autres classe de que nous avons trouver via la methode cacheService.
85
     */
86
    protected static array $services = [];
87
88
    /**
89
     * Avons-nous déjà découvert d'autres Services ?
90
     */
91
    protected static bool $discovered = false;
92
93
    /**
94
     * Un cache des noms de classes de services trouvés.
95
     *
96
     * @var array<string>
97
     */
98
    private static array $serviceNames = [];
99
100
    /**
101
     * La classe Autoloader permet de charger les fichiers simplement.
102
     */
103
    public static function autoloader(bool $shared = true): Autoloader
104
    {
105
        if (true === $shared && isset(static::$instances[Autoloader::class])) {
106 60
            return static::$instances[Autoloader::class];
107
        }
108
109 2
        $config  = static::config()->get('autoload');
110 2
        $helpers = array_merge(['url'], ($config['helpers'] ?? []));
111
112 2
        return static::$instances[Autoloader::class] = new Autoloader(/** @scrutinizer ignore-type */ $config, $helpers);
113
    }
114
115
    /**
116
     * La classe de cache fournit un moyen simple de stocker et de récupérer
117
     * données complexes pour plus tard
118
     */
119
    public static function cache(?array $config = null, bool $shared = true): Cache
120
    {
121
        if ($config === null || $config === []) {
122 8
            $config = static::config()->get('cache');
123
        }
124
125
        if (true === $shared && isset(static::$instances[Cache::class])) {
126 8
            $instance = static::$instances[Cache::class];
127
            if (empty(func_get_args()[0])) {
128 8
                return $instance;
129
            }
130
131
            return $instance->setConfig($config);
132
        }
133
134 2
        return static::$instances[Cache::class] = new Cache($config);
135
    }
136
137
    /**
138
     * Les composants sont destinées à vous permettre d'insérer du HTML dans la vue
139
     * qui a été généré par n'importe quel appel dans le système.
140
     */
141
    public static function componentLoader(bool $shared = true): ComponentLoader
142
    {
143
        if (true === $shared && isset(static::$instances[ComponentLoader::class])) {
144 2
            return static::$instances[ComponentLoader::class];
145
        }
146
147 2
        return static::$instances[ComponentLoader::class] = new ComponentLoader(static::cache());
148
    }
149
150
    /**
151
     * La clase Config offre une api fluide por gerer les configurations de l'application
152
     */
153
    public static function config(bool $shared = true): Config
154
    {
155
        if (true === $shared && isset(static::$instances[Config::class])) {
156 185
            return static::$instances[Config::class];
157
        }
158
159
        return static::$instances[Config::class] = new Config();
160
    }
161
162
    /**
163
     * Conteneur d'injection de dependances
164
     */
165
    public static function container(bool $shared = true): Container
166
    {
167
        if (true === $shared && isset(static::$instances[Container::class])) {
168 77
            return static::$instances[Container::class];
169
        }
170
171
        return static::$instances[Container::class] = new Container();
172
    }
173
174
    /**
175
     * Gestionnaire de cookies
176
     */
177
    public static function cookie(bool $shared = true): CookieManagerInterface
178
    {
179
        if (true === $shared && isset(static::$instances[CookieManager::class])) {
180 2
            return static::$instances[CookieManager::class];
181
        }
182
183 2
        $config = (object) static::config()->get('cookie');
184
185
        return static::$instances[CookieManager::class] = (new CookieManager())->setDefaultPathAndDomain(
186
            $config->path ?: '/',
187
            $config->domain ?: '',
188
            $config->secure ?: false,
189
            $config->httponly ?: true,
190
            $config->samesite ?: 'Lax'
191 2
        );
192
    }
193
194
    /**
195
     * Émetteur de réponse au client
196
     */
197
    public static function emitter(bool $shared = true): ResponseEmitter
198
    {
199
        if (true === $shared && isset(static::$instances[ResponseEmitter::class])) {
200 2
            return static::$instances[ResponseEmitter::class];
201
        }
202
203 2
        return static::$instances[ResponseEmitter::class] = new ResponseEmitter();
204
    }
205
206
    /**
207
     * La classe Encryption fournit un cryptage bidirectionnel.
208
     */
209
    public static function encrypter(?array $config = null, bool $shared = false): EncrypterInterface
210
    {
211
        if (true === $shared && isset(static::$instances[Encryption::class])) {
212
            return static::$instances[Encryption::class];
213
        }
214
215
        $config ??= config('encryption');
216
        $config     = (object) $config;
217
        $encryption = new Encryption($config);
218
219
        return static::$instances[Encryption::class] = $encryption->initialize($config);
220
    }
221
222
    /**
223
     * Gestionnaire d'evenement
224
     */
225
    public static function event(bool $shared = true): EventManager
226
    {
227
        if (true === $shared && isset(static::$instances[EventManager::class])) {
228
            return static::$instances[EventManager::class];
229
        }
230
231
        return static::$instances[EventManager::class] = new EventManager();
232
    }
233
234
    /**
235
     * System de gestion de fichier
236
     */
237
    public static function fs(bool $shared = true): Filesystem
238
    {
239
        if (true === $shared && isset(static::$instances[Filesystem::class])) {
240 4
            return static::$instances[Filesystem::class];
241
        }
242
243 2
        return static::$instances[Filesystem::class] = new Filesystem();
244
    }
245
246
    /**
247
     * Responsable du chargement des traductions des chaînes de langue.
248
     *
249
     * @deprecated 0.9 use translators instead
250
     */
251
    public static function language(?string $locale = null, bool $shared = true): Translate
252
    {
253 2
        return static::translator($locale, $shared);
254
    }
255
256
    /**
257
     * Le file locator fournit des methodes utilitaire pour chercher les fichiers non-classes
258
     * dans les dossiers de namespace. C'est une excelente methode pour charger les 'vues', 'helpers', et 'libraries'.
259
     */
260
    public static function locator(bool $shared = true): LocatorInterface
261
    {
262
        if ($shared && isset(static::$instances[Locator::class])) {
263 123
            return static::$instances[Locator::class];
264
        }
265
266
        return static::$instances[Locator::class] = new Locator(static::autoloader());
267
    }
268
269
    /**
270
     * La classe Logger est une classe Logging compatible PSR-3 qui prend en charge
271
     * plusieurs gestionnaires qui traitent la journalisation réelle.
272
     *
273
     * @return Logger
274
     */
275
    public static function logger(bool $shared = true): LoggerInterface
276
    {
277
        if ($shared && isset(static::$instances[Logger::class])) {
278 25
            return static::$instances[Logger::class];
279
        }
280
281
        return static::$instances[Logger::class] = new Logger();
282
    }
283
284
    /**
285
     * La classe de mail vous permet d'envoyer par courrier électronique via mail, sendmail, SMTP.
286
     */
287
    public static function mail(?array $config = null, bool $shared = true): Mail
288
    {
289
        if ($config === null || $config === []) {
290
            $config = static::config()->get('mail');
291
        }
292
293
        if (true === $shared && isset(static::$instances[Mail::class])) {
294
            /** @var Mail $instance */
295
            $instance = static::$instances[Mail::class];
296
            if (empty(func_get_args()[0])) {
297
                return $instance;
298
            }
299
300
            return $instance->merge($config);
301
        }
302
303
        return static::$instances[Mail::class] = new Mail($config);
304
    }
305
306
    /**
307
     * La classe Input générale modélise une requête HTTP.
308
     */
309
    public static function negotiator(?ServerRequest $request = null, bool $shared = true): Negotiator
310
    {
311
        if ($request === null) {
312 2
            $request = static::request(true);
313
        }
314
315
        if (true === $shared && isset(static::$instances[Negotiator::class])) {
316 2
            $instance = static::$instances[Negotiator::class];
317
            if (empty(func_get_args()[0])) {
318 2
                return $instance;
319
            }
320
321
            return $instance->setRequest($request);
322
        }
323
324 2
        return static::$instances[Negotiator::class] = new Negotiator($request);
325
    }
326
327
    /**
328
     * La classe des redirections HTTP
329
     */
330
    public static function redirection(bool $shared = true): Redirection
331
    {
332
        if (true === $shared && isset(static::$instances[Redirection::class])) {
333
            return static::$instances[Redirection::class];
334
        }
335
336
        return static::$instances[Redirection::class] = new Redirection(static::factory(UrlGenerator::class));
337
    }
338
339
    /**
340
     * La classe Resquest modélise une reqûete HTTP.
341
     */
342
    public static function request(bool $shared = true): Request
343
    {
344
        if (true === $shared && isset(static::$instances[Request::class])) {
345 45
            return static::$instances[Request::class];
346
        }
347
348
        return static::$instances[Request::class] = ServerRequestFactory::fromGlobals();
349
    }
350
351
    /**
352
     * La classe Response modélise une réponse HTTP.
353
     */
354
    public static function response(bool $shared = true): Response
355
    {
356
        if (true === $shared && isset(static::$instances[Response::class])) {
357 8
            return static::$instances[Response::class];
358
        }
359
360 1
        return static::$instances[Response::class] = new Response();
361
    }
362
363
    /**
364
     * CacheResponse
365
     */
366
    public static function responsecache(bool $shared = true): ResponseCache
367
    {
368
        if (true === $shared && isset(static::$instances[ResponseCache::class])) {
369
            return static::$instances[ResponseCache::class];
370
        }
371
372
        return static::$instances[ResponseCache::class] = new ResponseCache(static::cache(), /** @scrutinizer ignore-type */ static::config()->get('cache.cache_query_string'));
373
    }
374
375
    /**
376
     * Le service Routes est une classe qui permet de construire facilement
377
     * une collection d'itinéraires.
378
     */
379
    public static function routes(bool $shared = true): RouteCollection
380
    {
381
        if (true === $shared && isset(static::$instances[RouteCollection::class])) {
382 2
            return static::$instances[RouteCollection::class];
383
        }
384
385 10
        return static::$instances[RouteCollection::class] = new RouteCollection(static::locator(), (object) static::config()->get('routing'));
386
    }
387
388
    /**
389
     * La classe Router utilise le tableau de routes d'une RouteCollection et détermine
390
     * le contrôleur et la méthode corrects à exécuter.
391
     */
392
    public static function router(?RouteCollection $routes = null, ?ServerRequest $request = null, bool $shared = true): Router
393
    {
394
        if (true === $shared && isset(static::$instances[Router::class])) {
395 10
            return static::$instances[Router::class];
396
        }
397
398
        if ($routes === null) {
399 10
            $routes = static::routes(true);
400
        }
401
        if ($request === null) {
402 10
            $request = static::request(true);
403
        }
404
405 10
        return static::$instances[Router::class] = new Router($routes, $request);
406
    }
407
408
    /**
409
     * Retourne le gestionnaire de session.
410
     */
411
    public static function session(bool $shared = true): Store
412
    {
413
        if (true === $shared && isset(static::$instances[Store::class])) {
414 8
            return static::$instances[Store::class];
415
        }
416
417 19
        $config = static::config()->get('session');
418 19
        $db     = null;
419
420
        if (Text::contains($config['handler'], [DatabaseSessionHandler::class, 'database'])) {
421 19
            $group = $config['group'] ?? static::config()->get('database.connection');
422
            $db    = static::singleton(ConnectionResolverInterface::class)->connection($group);
423
424
            $driver = $db->getPlatform();
425
426
            if (Text::contains($driver, ['mysql', MySQLSessionHandler::class])) {
427
                $config['handler'] = MySQLSessionHandler::class;
428
            } elseif (Text::contains($driver, ['postgre', PostgreSessionHandler::class])) {
429
                $config['handler'] = PostgreSessionHandler::class;
430
            }
431
        }
432
433 19
        Cookie::setDefaults($cookies = /** @scrutinizer ignore-type */ static::config()->get('cookie'));
0 ignored issues
show
Bug introduced by
It seems like $cookies = static::config()->get('cookie') can also be of type null; however, parameter $options of BlitzPHP\Session\Cookie\Cookie::setDefaults() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

433
        Cookie::setDefaults(/** @scrutinizer ignore-type */ $cookies = /** @scrutinizer ignore-type */ static::config()->get('cookie'));
Loading history...
434 19
        $session = new Store((array) $config, (array) $cookies, Helpers::ipAddress());
435 19
        $session->setLogger(static::logger());
436 19
        $session->setDatabase($db);
437
438
        if (session_status() === PHP_SESSION_NONE) {
439 19
            $session->start();
440
        }
441
442 19
        return static::$instances[Store::class] = $session;
443
    }
444
445
    /**
446
     * System de gestion de fichier par disque
447
     */
448
    public static function storage(bool $shared = true): FilesystemManager
449
    {
450
        if ($shared && isset(static::$instances[FilesystemManager::class])) {
451 2
            return static::$instances[FilesystemManager::class];
452
        }
453
454 2
        return static::$instances[FilesystemManager::class] = new FilesystemManager(/** @scrutinizer ignore-type */ static::config()->get('filesystems'));
455
    }
456
457
    /**
458
     * La classe Timer fournit un moyen simple d'évaluer des parties de votre application.
459
     */
460
    public static function timer(bool $shared = true): Timer
461
    {
462
        if (true === $shared && isset(static::$instances[Timer::class])) {
463
            return static::$instances[Timer::class];
464
        }
465
466
        return static::$instances[Timer::class] = new Timer();
467
    }
468
469
    /**
470
     * Renvoie la barre d'outils de débogage.
471
     */
472
    public static function toolbar(?stdClass $config = null, bool $shared = true): Toolbar
473
    {
474
        if ($shared && isset(static::$instances[Toolbar::class])) {
475
            return static::$instances[Toolbar::class];
476
        }
477
478
        $config ??= (object) static::config()->get('toolbar');
479
480
        return static::$instances[Toolbar::class] = new Toolbar($config);
481
    }
482
483
    /**
484
     * Responsable du chargement des traductions des chaînes de langue.
485
     */
486
    public static function translator(?string $locale = null, bool $shared = true): Translate
487
    {
488
        if (empty($locale) && empty($locale = static::$instances[Translate::class . 'locale'] ?? null)) {
489 2
            $config = static::config()->get('app');
490
            if (($locale = static::negotiator()->language($config['supported_locales'])) === '' || ($locale = static::negotiator()->language($config['supported_locales'])) === '0') {
0 ignored issues
show
Unused Code introduced by
The assignment to $locale is dead and can be removed.
Loading history...
491 2
                $locale = $config['language'];
492
            }
493 2
            static::$instances[Translate::class . 'locale'] = $locale;
494
        }
495
496
        if (true === $shared && isset(static::$instances[Translate::class])) {
497 44
            return static::$instances[Translate::class]->setLocale($locale);
498
        }
499
500 4
        return static::$instances[Translate::class] = new Translate($locale, static::locator());
501
    }
502
503
    /**
504
     * La classe URI fournit un moyen de modéliser et de manipuler les URI.
505
     */
506
    public static function uri(?string $uri = null, bool $shared = true): Uri
507
    {
508
        if (true === $shared && isset(static::$instances[Uri::class])) {
509
            return static::$instances[Uri::class]->setURI($uri);
510
        }
511
512
        return static::$instances[Uri::class] = new Uri($uri);
513
    }
514
515
    /**
516
     * La classe Renderer est la classe qui affiche réellement un fichier à l'utilisateur.
517
     * La classe View par défaut dans BlitzPHP est intentionnellement simple, mais
518
     * le service peut facilement être remplacé par un moteur de modèle si l'utilisateur en a besoin.
519
     */
520
    public static function viewer(bool $shared = true): View
521
    {
522
        if (true === $shared && isset(static::$instances[View::class])) {
523 2
            return static::$instances[View::class];
524
        }
525
526 2
        return static::$instances[View::class] = new View();
527
    }
528
529
    /**
530
     * Offre la possibilité d'effectuer des appels insensibles à la casse des noms de service.
531
     *
532
     * @return mixed
533
     */
534
    public static function __callStatic(string $name, array $arguments)
535
    {
536
        if (null === $service = static::serviceExists($name)) {
537 4
            return static::discoverServices($name, $arguments);
538
        }
539
540
        return $service::$name(...$arguments);
541
    }
542
543
    /**
544
     * Vérifiez si le service demandé est défini et renvoyez la classe déclarante.
545
     * Renvoie null s'il n'est pas trouvé.
546
     */
547
    public static function serviceExists(string $name): ?string
548
    {
549 4
        static::cacheServices();
550 4
        $services = array_merge(self::$serviceNames, [self::class]);
551 4
        $name     = strtolower($name);
552
553
        foreach ($services as $service) {
554
            if (method_exists($service, $name)) {
555
                return $service;
556
            }
557
        }
558
559 4
        return null;
560
    }
561
562
    /**
563
     * Injectez un objet fictif pour les tests.
564
     */
565
    public static function injectMock(string $name, object $mock): void
566
    {
567 3
        static::$mocks[strtolower($name)] = $mock;
568
    }
569
570
    /**
571
     * Essaie d'obtenir un service à partir du conteneur
572
     *
573
     * @return mixed
574
     */
575
    protected static function discoverServices(string $name, array $arguments)
576
    {
577
        if (true !== array_pop($arguments)) {
578 4
            return static::factory($name, $arguments);
579
        }
580
581
        return static::singleton($name, ...$arguments);
582
    }
583
584
    protected static function cacheServices(): void
585
    {
586
        if (! static::$discovered) {
587 2
            $locator = static::locator();
588 2
            $files   = $locator->search('Config/Services');
589
590
            // Obtenez des instances de toutes les classes de service et mettez-les en cache localement.
591
            foreach ($files as $file) {
592
                if (false === $classname = $locator->findQualifiedNameFromPath($file)) {
593
                    continue;
594
                }
595
                if (self::class !== $classname) {
596
                    self::$serviceNames[] = $classname;
597
                    static::$services[]   = new $classname();
598
                }
599
            }
600
601 2
            static::$discovered = true;
602
        }
603
    }
604
605
    /**
606
     * Injecter une seule instance de la classe donnée
607
     *
608
     * @return mixed
609
     */
610
    public static function singleton(string $name)
611
    {
612
        $arguments = func_get_args();
613
        $name      = array_shift($arguments);
614
615
        if (empty(static::$instances[$name])) {
616
            static::$instances[$name] = $arguments !== [] ? static::factory($name, $arguments) : static::container()->get($name);
617
        }
618
619
        return static::$instances[$name];
620
    }
621
622
    /**
623
     * Injecter une nouvelle instance de la classe donnée
624
     *
625
     * @return mixed
626
     */
627
    public static function factory(string $name, array $arguments = [])
628
    {
629 4
        return static::container()->make($name, $arguments);
630
    }
631
632
    /**
633
     * Définissez un objet ou une valeur dans le conteneur.
634
     *
635
     * @param string $name  Nom de l'entrée
636
     * @param mixed  $value utilisez les aides à la définition pour définir les objets
637
     */
638
    public static function set(string $name, $value)
639
    {
640 42
        static::$instances[$name] = $value;
641 42
        static::container()->set($name, $value);
642
    }
643
644
    /**
645
     * Réinitialisez les instances partagées et les simulations pour les tests.
646
     */
647
    public static function reset(bool $initAutoloader = true): void
648
    {
649
        // static::$mocks     = [];
650
        static::$instances = [];
651
652
        if ($initAutoloader) {
653
            static::autoloader()->initialize();
654
        }
655
    }
656
}
657