From 6942197228c7d8d1db56cf956f8e50c07e69b3b5 Mon Sep 17 00:00:00 2001 From: agis Date: Fri, 18 Sep 2026 16:09:35 +0700 Subject: [PATCH 1/4] refactor(container): sweep bindShared() callers to singleton() (task 4.1, SCC-1 container-prep) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares the SCC-1 atomic window: v13's illuminate/container has singleton() but no bindShared()/share(). Migrate all 84 fork callers (32 service providers) from ->bindShared() to ->singleton() while the fork container still ships both. Semantics: fork bindShared($a,$c) = bind($a, share($c), true); singleton($a,$c) = bind($a,$c,true). The share() wrapper is a redundant static-var memoization on top of the shared-instance cache — dropping it converges to v13 behavior. Fork suite green (1646, 0 fail). bindShared()/share() methods are KEPT in the container (app service providers still call them until the app matched-pair conform); they go with the container swap in the atomic window. The Foundation\Application BindingResolutionException import redirect is also deferred to the window (fork concrete extends \Exception, not the Contracts type). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/Illuminate/Auth/AuthServiceProvider.php | 2 +- .../Auth/Reminders/ReminderServiceProvider.php | 10 +++++----- src/Illuminate/Cache/CacheServiceProvider.php | 10 +++++----- .../Cookie/CookieServiceProvider.php | 2 +- .../Database/DatabaseServiceProvider.php | 4 ++-- .../Database/MigrationServiceProvider.php | 18 +++++++++--------- .../Database/SeedServiceProvider.php | 4 ++-- .../Encryption/EncryptionServiceProvider.php | 2 +- .../Providers/ArtisanServiceProvider.php | 6 +++--- .../CommandCreatorServiceProvider.php | 2 +- .../Providers/ComposerServiceProvider.php | 4 ++-- .../Providers/KeyGeneratorServiceProvider.php | 2 +- .../Providers/MaintenanceServiceProvider.php | 4 ++-- .../Providers/OptimizeServiceProvider.php | 4 ++-- .../Providers/PublisherServiceProvider.php | 16 ++++++++-------- .../Providers/RouteListServiceProvider.php | 2 +- .../Providers/ServerServiceProvider.php | 2 +- .../Providers/TinkerServiceProvider.php | 2 +- src/Illuminate/Hashing/HashServiceProvider.php | 2 +- src/Illuminate/Html/HtmlServiceProvider.php | 4 ++-- src/Illuminate/Mail/MailServiceProvider.php | 6 +++--- .../Pagination/PaginationServiceProvider.php | 2 +- .../Queue/FailConsoleServiceProvider.php | 10 +++++----- src/Illuminate/Queue/QueueServiceProvider.php | 18 +++++++++--------- src/Illuminate/Redis/RedisServiceProvider.php | 2 +- .../Routing/ControllerServiceProvider.php | 2 +- .../Session/CommandsServiceProvider.php | 2 +- .../Session/SessionServiceProvider.php | 4 ++-- .../Translation/TranslationServiceProvider.php | 4 ++-- .../Validation/ValidationServiceProvider.php | 4 ++-- src/Illuminate/View/ViewServiceProvider.php | 8 ++++---- .../Workbench/WorkbenchServiceProvider.php | 4 ++-- 32 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/Illuminate/Auth/AuthServiceProvider.php b/src/Illuminate/Auth/AuthServiceProvider.php index 9a6bd7f0a..4a5c509d8 100755 --- a/src/Illuminate/Auth/AuthServiceProvider.php +++ b/src/Illuminate/Auth/AuthServiceProvider.php @@ -18,7 +18,7 @@ class AuthServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('auth', function($app) + $this->app->singleton('auth', function($app) { // Once the authentication service has actually been requested by the developer // we will set a variable in the application indicating such. This helps us diff --git a/src/Illuminate/Auth/Reminders/ReminderServiceProvider.php b/src/Illuminate/Auth/Reminders/ReminderServiceProvider.php index 0c3664023..125c0bd1a 100755 --- a/src/Illuminate/Auth/Reminders/ReminderServiceProvider.php +++ b/src/Illuminate/Auth/Reminders/ReminderServiceProvider.php @@ -36,7 +36,7 @@ public function register() */ protected function registerPasswordBroker() { - $this->app->bindShared('auth.reminder', function($app) + $this->app->singleton('auth.reminder', function($app) { // The reminder repository is responsible for storing the user e-mail addresses // and password reset tokens. It will be used to verify the tokens are valid @@ -65,7 +65,7 @@ protected function registerPasswordBroker() */ protected function registerReminderRepository() { - $this->app->bindShared('auth.reminder.repository', function($app) + $this->app->singleton('auth.reminder.repository', function($app) { $connection = $app['db']->connection(); @@ -89,17 +89,17 @@ protected function registerReminderRepository() */ protected function registerCommands() { - $this->app->bindShared('command.auth.reminders', function($app) + $this->app->singleton('command.auth.reminders', function($app) { return new RemindersTableCommand($app['files']); }); - $this->app->bindShared('command.auth.reminders.clear', function() + $this->app->singleton('command.auth.reminders.clear', function() { return new ClearRemindersCommand; }); - $this->app->bindShared('command.auth.reminders.controller', function($app) + $this->app->singleton('command.auth.reminders.controller', function($app) { return new RemindersControllerCommand($app['files']); }); diff --git a/src/Illuminate/Cache/CacheServiceProvider.php b/src/Illuminate/Cache/CacheServiceProvider.php index 4c17e24c6..0e3c611cc 100755 --- a/src/Illuminate/Cache/CacheServiceProvider.php +++ b/src/Illuminate/Cache/CacheServiceProvider.php @@ -18,17 +18,17 @@ class CacheServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('cache', function($app) + $this->app->singleton('cache', function($app) { return new CacheManager($app); }); - $this->app->bindShared('cache.store', function($app) + $this->app->singleton('cache.store', function($app) { return $app['cache']->driver(); }); - $this->app->bindShared('memcached.connector', function() + $this->app->singleton('memcached.connector', function() { return new MemcachedConnector; }); @@ -43,12 +43,12 @@ public function register() */ public function registerCommands() { - $this->app->bindShared('command.cache.clear', function($app) + $this->app->singleton('command.cache.clear', function($app) { return new Console\ClearCommand($app['cache'], $app['files']); }); - $this->app->bindShared('command.cache.table', function($app) + $this->app->singleton('command.cache.table', function($app) { return new Console\CacheTableCommand($app['files']); }); diff --git a/src/Illuminate/Cookie/CookieServiceProvider.php b/src/Illuminate/Cookie/CookieServiceProvider.php index 1c7b9d055..f463302e6 100755 --- a/src/Illuminate/Cookie/CookieServiceProvider.php +++ b/src/Illuminate/Cookie/CookieServiceProvider.php @@ -11,7 +11,7 @@ class CookieServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('cookie', function($app) + $this->app->singleton('cookie', function($app) { $config = $app['config']['session']; diff --git a/src/Illuminate/Database/DatabaseServiceProvider.php b/src/Illuminate/Database/DatabaseServiceProvider.php index 492642225..32005da56 100755 --- a/src/Illuminate/Database/DatabaseServiceProvider.php +++ b/src/Illuminate/Database/DatabaseServiceProvider.php @@ -28,7 +28,7 @@ public function register() // The connection factory is used to create the actual connection instances on // the database. We will inject the factory into the manager so that it may // make the connections while they are actually needed and not of before. - $this->app->bindShared('db.factory', function($app) + $this->app->singleton('db.factory', function($app) { return new ConnectionFactory($app); }); @@ -36,7 +36,7 @@ public function register() // The database manager is used to resolve various connections, since multiple // connections might be managed. It also implements the connection resolver // interface which may be used by other components requiring connections. - $this->app->bindShared('db', function($app) + $this->app->singleton('db', function($app) { return new DatabaseManager($app, $app['db.factory']); }); diff --git a/src/Illuminate/Database/MigrationServiceProvider.php b/src/Illuminate/Database/MigrationServiceProvider.php index 4bf1d2e73..58782c869 100755 --- a/src/Illuminate/Database/MigrationServiceProvider.php +++ b/src/Illuminate/Database/MigrationServiceProvider.php @@ -44,7 +44,7 @@ public function register() */ protected function registerRepository() { - $this->app->bindShared('migration.repository', function($app) + $this->app->singleton('migration.repository', function($app) { $table = $app['config']['database.migrations']; @@ -62,7 +62,7 @@ protected function registerMigrator() // The migrator is responsible for actually running and rollback the migration // files in the application. We'll pass in our database connection resolver // so the migrator can resolve any of these connections when it needs to. - $this->app->bindShared('migrator', function($app) + $this->app->singleton('migrator', function($app) { $repository = $app['migration.repository']; @@ -104,7 +104,7 @@ protected function registerCommands() */ protected function registerMigrateCommand() { - $this->app->bindShared('command.migrate', function($app) + $this->app->singleton('command.migrate', function($app) { $packagePath = $app['path.base'].'/vendor'; @@ -119,7 +119,7 @@ protected function registerMigrateCommand() */ protected function registerRollbackCommand() { - $this->app->bindShared('command.migrate.rollback', function($app) + $this->app->singleton('command.migrate.rollback', function($app) { return new RollbackCommand($app['migrator']); }); @@ -132,7 +132,7 @@ protected function registerRollbackCommand() */ protected function registerResetCommand() { - $this->app->bindShared('command.migrate.reset', function($app) + $this->app->singleton('command.migrate.reset', function($app) { return new ResetCommand($app['migrator']); }); @@ -145,7 +145,7 @@ protected function registerResetCommand() */ protected function registerRefreshCommand() { - $this->app->bindShared('command.migrate.refresh', function() + $this->app->singleton('command.migrate.refresh', function() { return new RefreshCommand; }); @@ -158,7 +158,7 @@ protected function registerRefreshCommand() */ protected function registerInstallCommand() { - $this->app->bindShared('command.migrate.install', function($app) + $this->app->singleton('command.migrate.install', function($app) { return new InstallCommand($app['migration.repository']); }); @@ -173,7 +173,7 @@ protected function registerMakeCommand() { $this->registerCreator(); - $this->app->bindShared('command.migrate.make', function($app) + $this->app->singleton('command.migrate.make', function($app) { // Once we have the migration creator registered, we will create the command // and inject the creator. The creator is responsible for the actual file @@ -193,7 +193,7 @@ protected function registerMakeCommand() */ protected function registerCreator() { - $this->app->bindShared('migration.creator', function($app) + $this->app->singleton('migration.creator', function($app) { return new MigrationCreator($app['files']); }); diff --git a/src/Illuminate/Database/SeedServiceProvider.php b/src/Illuminate/Database/SeedServiceProvider.php index 00203aa1f..886518ecb 100755 --- a/src/Illuminate/Database/SeedServiceProvider.php +++ b/src/Illuminate/Database/SeedServiceProvider.php @@ -21,7 +21,7 @@ public function register() { $this->registerSeedCommand(); - $this->app->bindShared('seeder', function() + $this->app->singleton('seeder', function() { return new Seeder; }); @@ -36,7 +36,7 @@ public function register() */ protected function registerSeedCommand() { - $this->app->bindShared('command.seed', function($app) + $this->app->singleton('command.seed', function($app) { return new SeedCommand($app['db']); }); diff --git a/src/Illuminate/Encryption/EncryptionServiceProvider.php b/src/Illuminate/Encryption/EncryptionServiceProvider.php index c6329d19e..507192e0e 100755 --- a/src/Illuminate/Encryption/EncryptionServiceProvider.php +++ b/src/Illuminate/Encryption/EncryptionServiceProvider.php @@ -11,7 +11,7 @@ class EncryptionServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('encrypter', function($app) + $this->app->singleton('encrypter', function($app) { return new Encrypter($app['config']['app.key']); }); diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 916175c9c..659e812d4 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -21,17 +21,17 @@ class ArtisanServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('artisan', function($app) + $this->app->singleton('artisan', function($app) { return new Artisan($app); }); - $this->app->bindShared('command.changes', function() + $this->app->singleton('command.changes', function() { return new ChangesCommand; }); - $this->app->bindShared('command.environment', function() + $this->app->singleton('command.environment', function() { return new EnvironmentCommand; }); diff --git a/src/Illuminate/Foundation/Providers/CommandCreatorServiceProvider.php b/src/Illuminate/Foundation/Providers/CommandCreatorServiceProvider.php index 560921949..3679effe8 100755 --- a/src/Illuminate/Foundation/Providers/CommandCreatorServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/CommandCreatorServiceProvider.php @@ -19,7 +19,7 @@ class CommandCreatorServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.command.make', function($app) + $this->app->singleton('command.command.make', function($app) { return new CommandMakeCommand($app['files']); }); diff --git a/src/Illuminate/Foundation/Providers/ComposerServiceProvider.php b/src/Illuminate/Foundation/Providers/ComposerServiceProvider.php index 2022d7f54..e1b421ef3 100755 --- a/src/Illuminate/Foundation/Providers/ComposerServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ComposerServiceProvider.php @@ -20,12 +20,12 @@ class ComposerServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('composer', function($app) + $this->app->singleton('composer', function($app) { return new Composer($app['files'], $app['path.base']); }); - $this->app->bindShared('command.dump-autoload', function($app) + $this->app->singleton('command.dump-autoload', function($app) { return new AutoloadCommand($app['composer']); }); diff --git a/src/Illuminate/Foundation/Providers/KeyGeneratorServiceProvider.php b/src/Illuminate/Foundation/Providers/KeyGeneratorServiceProvider.php index f73f93056..197077ddc 100755 --- a/src/Illuminate/Foundation/Providers/KeyGeneratorServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/KeyGeneratorServiceProvider.php @@ -19,7 +19,7 @@ class KeyGeneratorServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.key.generate', function($app) + $this->app->singleton('command.key.generate', function($app) { return new KeyGenerateCommand($app['files']); }); diff --git a/src/Illuminate/Foundation/Providers/MaintenanceServiceProvider.php b/src/Illuminate/Foundation/Providers/MaintenanceServiceProvider.php index 703f6d3c0..6de7a4bdc 100755 --- a/src/Illuminate/Foundation/Providers/MaintenanceServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/MaintenanceServiceProvider.php @@ -20,12 +20,12 @@ class MaintenanceServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.up', function() + $this->app->singleton('command.up', function() { return new UpCommand; }); - $this->app->bindShared('command.down', function() + $this->app->singleton('command.down', function() { return new DownCommand; }); diff --git a/src/Illuminate/Foundation/Providers/OptimizeServiceProvider.php b/src/Illuminate/Foundation/Providers/OptimizeServiceProvider.php index cc809bc5b..f780fa857 100755 --- a/src/Illuminate/Foundation/Providers/OptimizeServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/OptimizeServiceProvider.php @@ -34,7 +34,7 @@ public function register() */ protected function registerOptimizeCommand() { - $this->app->bindShared('command.optimize', function($app) + $this->app->singleton('command.optimize', function($app) { return new OptimizeCommand($app['composer']); }); @@ -47,7 +47,7 @@ protected function registerOptimizeCommand() */ protected function registerClearCompiledCommand() { - $this->app->bindShared('command.clear-compiled', function() + $this->app->singleton('command.clear-compiled', function() { return new ClearCompiledCommand; }); diff --git a/src/Illuminate/Foundation/Providers/PublisherServiceProvider.php b/src/Illuminate/Foundation/Providers/PublisherServiceProvider.php index ee324c9cf..085b83a96 100755 --- a/src/Illuminate/Foundation/Providers/PublisherServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/PublisherServiceProvider.php @@ -49,7 +49,7 @@ protected function registerAssetPublisher() { $this->registerAssetPublishCommand(); - $this->app->bindShared('asset.publisher', function($app) + $this->app->singleton('asset.publisher', function($app) { $publicPath = $app['path.public']; @@ -71,7 +71,7 @@ protected function registerAssetPublisher() */ protected function registerAssetPublishCommand() { - $this->app->bindShared('command.asset.publish', function($app) + $this->app->singleton('command.asset.publish', function($app) { return new AssetPublishCommand($app['asset.publisher']); }); @@ -86,7 +86,7 @@ protected function registerConfigPublisher() { $this->registerConfigPublishCommand(); - $this->app->bindShared('config.publisher', function($app) + $this->app->singleton('config.publisher', function($app) { $path = $app['path'].'/config'; @@ -108,7 +108,7 @@ protected function registerConfigPublisher() */ protected function registerConfigPublishCommand() { - $this->app->bindShared('command.config.publish', function($app) + $this->app->singleton('command.config.publish', function($app) { return new ConfigPublishCommand($app['config.publisher']); }); @@ -123,7 +123,7 @@ protected function registerViewPublisher() { $this->registerViewPublishCommand(); - $this->app->bindShared('view.publisher', function($app) + $this->app->singleton('view.publisher', function($app) { $viewPath = $app['path'].'/views'; @@ -145,7 +145,7 @@ protected function registerViewPublisher() */ protected function registerViewPublishCommand() { - $this->app->bindShared('command.view.publish', function($app) + $this->app->singleton('command.view.publish', function($app) { return new ViewPublishCommand($app['view.publisher']); }); @@ -160,7 +160,7 @@ protected function registerMigrationPublisher() { $this->registerMigratePublishCommand(); - $this->app->bindShared('migration.publisher', function($app) + $this->app->singleton('migration.publisher', function($app) { return new MigrationPublisher($app['files']); }); @@ -173,7 +173,7 @@ protected function registerMigrationPublisher() */ protected function registerMigratePublishCommand() { - $this->app->bindShared('command.migrate.publish', function() + $this->app->singleton('command.migrate.publish', function() { return new MigratePublishCommand; }); diff --git a/src/Illuminate/Foundation/Providers/RouteListServiceProvider.php b/src/Illuminate/Foundation/Providers/RouteListServiceProvider.php index af1e9bae8..02179b545 100755 --- a/src/Illuminate/Foundation/Providers/RouteListServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/RouteListServiceProvider.php @@ -19,7 +19,7 @@ class RouteListServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.routes', function($app) + $this->app->singleton('command.routes', function($app) { return new RoutesCommand($app['router']); }); diff --git a/src/Illuminate/Foundation/Providers/ServerServiceProvider.php b/src/Illuminate/Foundation/Providers/ServerServiceProvider.php index f6af6197e..3e3762b93 100755 --- a/src/Illuminate/Foundation/Providers/ServerServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ServerServiceProvider.php @@ -19,7 +19,7 @@ class ServerServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.serve', function() + $this->app->singleton('command.serve', function() { return new ServeCommand; }); diff --git a/src/Illuminate/Foundation/Providers/TinkerServiceProvider.php b/src/Illuminate/Foundation/Providers/TinkerServiceProvider.php index 55a4a2303..502bbf1cc 100755 --- a/src/Illuminate/Foundation/Providers/TinkerServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/TinkerServiceProvider.php @@ -19,7 +19,7 @@ class TinkerServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.tinker', function() + $this->app->singleton('command.tinker', function() { return new TinkerCommand; }); diff --git a/src/Illuminate/Hashing/HashServiceProvider.php b/src/Illuminate/Hashing/HashServiceProvider.php index 59af2927c..486bf6e4a 100755 --- a/src/Illuminate/Hashing/HashServiceProvider.php +++ b/src/Illuminate/Hashing/HashServiceProvider.php @@ -18,7 +18,7 @@ class HashServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('hash', function() { return new BcryptHasher; }); + $this->app->singleton('hash', function() { return new BcryptHasher; }); } /** diff --git a/src/Illuminate/Html/HtmlServiceProvider.php b/src/Illuminate/Html/HtmlServiceProvider.php index 8cec79adf..0c1f24138 100755 --- a/src/Illuminate/Html/HtmlServiceProvider.php +++ b/src/Illuminate/Html/HtmlServiceProvider.php @@ -30,7 +30,7 @@ public function register() */ protected function registerHtmlBuilder() { - $this->app->bindShared('html', function($app) + $this->app->singleton('html', function($app) { return new HtmlBuilder($app['url']); }); @@ -43,7 +43,7 @@ protected function registerHtmlBuilder() */ protected function registerFormBuilder() { - $this->app->bindShared('form', function($app) + $this->app->singleton('form', function($app) { $form = new FormBuilder($app['html'], $app['url'], $app['session.store']->getToken()); diff --git a/src/Illuminate/Mail/MailServiceProvider.php b/src/Illuminate/Mail/MailServiceProvider.php index 47053d382..4728a1d0b 100755 --- a/src/Illuminate/Mail/MailServiceProvider.php +++ b/src/Illuminate/Mail/MailServiceProvider.php @@ -27,7 +27,7 @@ public function register(): void { $me = $this; - $this->app->bindShared('mailer', function($app) use ($me) + $this->app->singleton('mailer', function($app) use ($me) { $me->registerSymfonyMailer(); @@ -190,7 +190,7 @@ protected function registerMailTransport(array $config): void */ // protected function registerMailgunTransport(array $config): void // { -// $this->app->bindShared('symfony.transport', function() use ($config) +// $this->app->singleton('symfony.transport', function() use ($config) // { // $factory = new MailgunTransportFactory(null, $this->getHttpClient($config)); // @@ -215,7 +215,7 @@ protected function registerMailTransport(array $config): void */ protected function registerLogTransport(array $config): void { - $this->app->bindShared('symfony.transport', fn($app) => new LogTransport($app->make('Psr\Log\LoggerInterface'))); + $this->app->singleton('symfony.transport', fn($app) => new LogTransport($app->make('Psr\Log\LoggerInterface'))); } // /** diff --git a/src/Illuminate/Pagination/PaginationServiceProvider.php b/src/Illuminate/Pagination/PaginationServiceProvider.php index 955ffb15e..933e82ca4 100755 --- a/src/Illuminate/Pagination/PaginationServiceProvider.php +++ b/src/Illuminate/Pagination/PaginationServiceProvider.php @@ -18,7 +18,7 @@ class PaginationServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('paginator', function($app) + $this->app->singleton('paginator', function($app) { $paginator = new Factory($app['request'], $app['view'], $app['translator']); diff --git a/src/Illuminate/Queue/FailConsoleServiceProvider.php b/src/Illuminate/Queue/FailConsoleServiceProvider.php index c510a0bc3..d2eeaf509 100644 --- a/src/Illuminate/Queue/FailConsoleServiceProvider.php +++ b/src/Illuminate/Queue/FailConsoleServiceProvider.php @@ -23,27 +23,27 @@ class FailConsoleServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.queue.failed', function() + $this->app->singleton('command.queue.failed', function() { return new ListFailedCommand; }); - $this->app->bindShared('command.queue.retry', function() + $this->app->singleton('command.queue.retry', function() { return new RetryCommand; }); - $this->app->bindShared('command.queue.forget', function() + $this->app->singleton('command.queue.forget', function() { return new ForgetFailedCommand; }); - $this->app->bindShared('command.queue.flush', function() + $this->app->singleton('command.queue.flush', function() { return new FlushFailedCommand; }); - $this->app->bindShared('command.queue.failed-table', function($app) + $this->app->singleton('command.queue.failed-table', function($app) { return new FailedTableCommand($app['files']); }); diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index f6829f257..26169c893 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -49,7 +49,7 @@ public function register() */ protected function registerManager() { - $this->app->bindShared('queue', function($app) + $this->app->singleton('queue', function($app) { // Once we have an instance of the queue manager, we will register the various // resolvers for the queue connectors. These connectors are responsible for @@ -73,7 +73,7 @@ protected function registerWorker() $this->registerRestartCommand(); - $this->app->bindShared('queue.worker', function($app) + $this->app->singleton('queue.worker', function($app) { return new Worker($app['queue'], $app['queue.failer'], $app['events']); }); @@ -86,7 +86,7 @@ protected function registerWorker() */ protected function registerWorkCommand() { - $this->app->bindShared('command.queue.work', function($app) + $this->app->singleton('command.queue.work', function($app) { return new WorkCommand($app['queue.worker']); }); @@ -103,7 +103,7 @@ protected function registerListener() { $this->registerListenCommand(); - $this->app->bindShared('queue.listener', function($app) + $this->app->singleton('queue.listener', function($app) { return new Listener($app['path.base']); }); @@ -116,7 +116,7 @@ protected function registerListener() */ protected function registerListenCommand() { - $this->app->bindShared('command.queue.listen', function($app) + $this->app->singleton('command.queue.listen', function($app) { return new ListenCommand($app['queue.listener']); }); @@ -131,7 +131,7 @@ protected function registerListenCommand() */ public function registerRestartCommand() { - $this->app->bindShared('command.queue.restart', function() + $this->app->singleton('command.queue.restart', function() { return new RestartCommand; }); @@ -146,7 +146,7 @@ public function registerRestartCommand() */ protected function registerSubscriber() { - $this->app->bindShared('command.queue.subscribe', function() + $this->app->singleton('command.queue.subscribe', function() { return new SubscribeCommand; }); @@ -267,7 +267,7 @@ protected function registerIronRequestBinder() */ protected function registerFailedJobServices() { - $this->app->bindShared('queue.failer', function($app) + $this->app->singleton('queue.failer', function($app) { $config = $app['config']['queue.failed']; @@ -282,7 +282,7 @@ protected function registerFailedJobServices() */ protected function registerQueueClosure() { - $this->app->bindShared('IlluminateQueueClosure', function($app) + $this->app->singleton('IlluminateQueueClosure', function($app) { return new IlluminateQueueClosure($app['encrypter']); }); diff --git a/src/Illuminate/Redis/RedisServiceProvider.php b/src/Illuminate/Redis/RedisServiceProvider.php index ae2fe9e84..39236a98c 100755 --- a/src/Illuminate/Redis/RedisServiceProvider.php +++ b/src/Illuminate/Redis/RedisServiceProvider.php @@ -18,7 +18,7 @@ class RedisServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('redis', function($app) + $this->app->singleton('redis', function($app) { return new Database($app['config']['database.redis']); }); diff --git a/src/Illuminate/Routing/ControllerServiceProvider.php b/src/Illuminate/Routing/ControllerServiceProvider.php index ba12f2502..0df75c996 100644 --- a/src/Illuminate/Routing/ControllerServiceProvider.php +++ b/src/Illuminate/Routing/ControllerServiceProvider.php @@ -32,7 +32,7 @@ public function register() */ protected function registerGenerator() { - $this->app->bindShared('command.controller.make', function($app) + $this->app->singleton('command.controller.make', function($app) { // The controller generator is responsible for building resourceful controllers // quickly and easily for the developers via the Artisan CLI. We'll go ahead diff --git a/src/Illuminate/Session/CommandsServiceProvider.php b/src/Illuminate/Session/CommandsServiceProvider.php index 5f7b01c71..81ef0baea 100755 --- a/src/Illuminate/Session/CommandsServiceProvider.php +++ b/src/Illuminate/Session/CommandsServiceProvider.php @@ -18,7 +18,7 @@ class CommandsServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('command.session.database', function($app) + $this->app->singleton('command.session.database', function($app) { return new Console\SessionTableCommand($app['files']); }); diff --git a/src/Illuminate/Session/SessionServiceProvider.php b/src/Illuminate/Session/SessionServiceProvider.php index 0efe172de..70fd15213 100755 --- a/src/Illuminate/Session/SessionServiceProvider.php +++ b/src/Illuminate/Session/SessionServiceProvider.php @@ -38,7 +38,7 @@ protected function setupDefaultDriver() */ protected function registerSessionManager() { - $this->app->bindShared('session', function($app) + $this->app->singleton('session', function($app) { return new SessionManager($app); }); @@ -51,7 +51,7 @@ protected function registerSessionManager() */ protected function registerSessionDriver() { - $this->app->bindShared('session.store', function($app) + $this->app->singleton('session.store', function($app) { // First, we will create the session manager which is responsible for the // creation of the various session drivers when they are needed by the diff --git a/src/Illuminate/Translation/TranslationServiceProvider.php b/src/Illuminate/Translation/TranslationServiceProvider.php index 4b696501d..e508e2eb6 100755 --- a/src/Illuminate/Translation/TranslationServiceProvider.php +++ b/src/Illuminate/Translation/TranslationServiceProvider.php @@ -20,7 +20,7 @@ public function register() { $this->registerLoader(); - $this->app->bindShared('translator', function($app) + $this->app->singleton('translator', function($app) { $loader = $app['translation.loader']; @@ -44,7 +44,7 @@ public function register() */ protected function registerLoader() { - $this->app->bindShared('translation.loader', function($app) + $this->app->singleton('translation.loader', function($app) { return new FileLoader($app['files'], $app['path'].'/lang'); }); diff --git a/src/Illuminate/Validation/ValidationServiceProvider.php b/src/Illuminate/Validation/ValidationServiceProvider.php index b6b2dbdd7..3c1ab1b71 100755 --- a/src/Illuminate/Validation/ValidationServiceProvider.php +++ b/src/Illuminate/Validation/ValidationServiceProvider.php @@ -20,7 +20,7 @@ public function register() { $this->registerPresenceVerifier(); - $this->app->bindShared('validator', function($app) + $this->app->singleton('validator', function($app) { $validator = new Factory($app['translator'], $app); @@ -43,7 +43,7 @@ public function register() */ protected function registerPresenceVerifier() { - $this->app->bindShared('validation.presence', function($app) + $this->app->singleton('validation.presence', function($app) { return new DatabasePresenceVerifier($app['db']); }); diff --git a/src/Illuminate/View/ViewServiceProvider.php b/src/Illuminate/View/ViewServiceProvider.php index e186da87f..7763b869f 100755 --- a/src/Illuminate/View/ViewServiceProvider.php +++ b/src/Illuminate/View/ViewServiceProvider.php @@ -35,7 +35,7 @@ public function register() */ public function registerEngineResolver() { - $this->app->bindShared('view.engine.resolver', function() + $this->app->singleton('view.engine.resolver', function() { $resolver = new EngineResolver; @@ -75,7 +75,7 @@ public function registerBladeEngine($resolver) // The Compiler engine requires an instance of the CompilerInterface, which in // this case will be the Blade compiler, so we'll first create the compiler // instance to pass into the engine so it can compile the views properly. - $app->bindShared('blade.compiler', function($app) + $app->singleton('blade.compiler', function($app) { $cache = $app['path.storage'].'/views'; @@ -95,7 +95,7 @@ public function registerBladeEngine($resolver) */ public function registerViewFinder() { - $this->app->bindShared('view.finder', function($app) + $this->app->singleton('view.finder', function($app) { $paths = $app['config']['view.paths']; @@ -110,7 +110,7 @@ public function registerViewFinder() */ public function registerFactory() { - $this->app->bindShared('view', function($app) + $this->app->singleton('view', function($app) { // Next we need to grab the engine resolver instance that will be used by the // environment. The resolver will be used by an environment to get each of diff --git a/src/Illuminate/Workbench/WorkbenchServiceProvider.php b/src/Illuminate/Workbench/WorkbenchServiceProvider.php index 4dcd4e25c..d2e41e826 100755 --- a/src/Illuminate/Workbench/WorkbenchServiceProvider.php +++ b/src/Illuminate/Workbench/WorkbenchServiceProvider.php @@ -19,12 +19,12 @@ class WorkbenchServiceProvider extends ServiceProvider { */ public function register() { - $this->app->bindShared('package.creator', function($app) + $this->app->singleton('package.creator', function($app) { return new PackageCreator($app['files']); }); - $this->app->bindShared('command.workbench', function($app) + $this->app->singleton('command.workbench', function($app) { return new WorkbenchMakeCommand($app['package.creator']); }); From f1fff797ebb444b6c2e8f8cbc029225ffc6ebf96 Mon Sep 17 00:00:00 2001 From: agis Date: Fri, 18 Sep 2026 16:19:22 +0700 Subject: [PATCH 2/4] refactor(container): convert $app->share() bindings to singleton() (task 4.1, SCC-1 container-prep) Second prep slice for the container swap: v13 illuminate/container has no share(). The 15 legacy `$this->app['key'] = $this->app->share($closure)` bindings (Events, Routing x4, CachedRouting, Exception x6, Mail x3) are the L4.0 idiom where share() memoizes a closure via a static var and offsetSet binds it non-shared. In v13 `$app['key'] = $closure` binds NON-shared, so the singleton must be explicit: rewritten to `$this->app->singleton('key', $closure)`. View Factory's own share() (view-data sharing, different API) is untouched. Fork suite green (1646, 0 fail). Missed in the bindShared sweep because an rtk-proxied grep wrongly reported zero ->share( callsites; re-verified via `rtk proxy grep`. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../CachedRouting/RoutingServiceProvider.php | 2 +- src/Illuminate/Events/EventServiceProvider.php | 2 +- .../Exception/ExceptionServiceProvider.php | 12 ++++++------ src/Illuminate/Mail/MailServiceProvider.php | 6 +++--- src/Illuminate/Routing/RoutingServiceProvider.php | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Illuminate/CachedRouting/RoutingServiceProvider.php b/src/Illuminate/CachedRouting/RoutingServiceProvider.php index eff880aae..472777e66 100644 --- a/src/Illuminate/CachedRouting/RoutingServiceProvider.php +++ b/src/Illuminate/CachedRouting/RoutingServiceProvider.php @@ -56,7 +56,7 @@ public function register() */ protected function registerRouter() { - $this->app['router'] = $this->app->share( + $this->app->singleton('router', function ($app) { $router = new Router($app['events'], $app); diff --git a/src/Illuminate/Events/EventServiceProvider.php b/src/Illuminate/Events/EventServiceProvider.php index 94b8e4be3..e78ac72e8 100755 --- a/src/Illuminate/Events/EventServiceProvider.php +++ b/src/Illuminate/Events/EventServiceProvider.php @@ -11,7 +11,7 @@ class EventServiceProvider extends ServiceProvider { */ public function register() { - $this->app['events'] = $this->app->share(function($app) + $this->app->singleton('events', function($app) { return new Dispatcher($app); }); diff --git a/src/Illuminate/Exception/ExceptionServiceProvider.php b/src/Illuminate/Exception/ExceptionServiceProvider.php index c2fa6a68c..0d65df231 100755 --- a/src/Illuminate/Exception/ExceptionServiceProvider.php +++ b/src/Illuminate/Exception/ExceptionServiceProvider.php @@ -38,7 +38,7 @@ protected function registerDisplayers() */ protected function registerHandler() { - $this->app['exception'] = $this->app->share(function($app) + $this->app->singleton('exception', function($app) { return new Handler($app, $app['exception.plain'], $app['exception.debug']); }); @@ -51,7 +51,7 @@ protected function registerHandler() */ protected function registerPlainDisplayer() { - $this->app['exception.plain'] = $this->app->share(function($app) + $this->app->singleton('exception.plain', function($app) { // If the application is running in a console environment, we will just always // use the debug handler as there is no point in the console ever returning @@ -76,7 +76,7 @@ protected function registerDebugDisplayer() { $this->registerWhoops(); - $this->app['exception.debug'] = $this->app->share(function($app) + $this->app->singleton('exception.debug', function($app) { return new WhoopsDisplayer($app['whoops'], $app->runningInConsole()); }); @@ -91,7 +91,7 @@ protected function registerWhoops() { $this->registerWhoopsHandler(); - $this->app['whoops'] = $this->app->share(function($app) + $this->app->singleton('whoops', function($app) { // We will instruct Whoops to not exit after it displays the exception as it // will otherwise run out before we can do anything else. We just want to @@ -113,7 +113,7 @@ protected function registerWhoopsHandler() { if ($this->shouldReturnJson()) { - $this->app['whoops.handler'] = $this->app->share(function() + $this->app->singleton('whoops.handler', function() { return new JsonResponseHandler; }); @@ -151,7 +151,7 @@ protected function requestWantsJson() */ protected function registerPrettyWhoopsHandler() { - $this->app['whoops.handler'] = $this->app->share(function() + $this->app->singleton('whoops.handler', function() { with($handler = new PrettyPageHandler)->setEditor('sublime'); diff --git a/src/Illuminate/Mail/MailServiceProvider.php b/src/Illuminate/Mail/MailServiceProvider.php index 4728a1d0b..396fab307 100755 --- a/src/Illuminate/Mail/MailServiceProvider.php +++ b/src/Illuminate/Mail/MailServiceProvider.php @@ -120,7 +120,7 @@ public function registerSymfonyMailer(): void */ protected function registerSmtpTransport(array $config): void { - $this->app['symfony.transport'] = $this->app->share(function($app) use ($config) + $this->app->singleton('symfony.transport', function($app) use ($config) { $factory = new EsmtpTransportFactory(); @@ -166,7 +166,7 @@ protected function registerSmtpTransport(array $config): void */ protected function registerSendmailTransport(array $config): void { - $this->app['symfony.transport'] = $this->app->share(fn($app) => new SendmailTransport( + $this->app->singleton('symfony.transport', fn($app) => new SendmailTransport( $config['path'] ?? $app['config']->get('mail.sendmail') )); } @@ -179,7 +179,7 @@ protected function registerSendmailTransport(array $config): void */ protected function registerMailTransport(array $config): void { - $this->app['symfony.transport'] = $this->app->share(fn() => new SendmailTransport()); + $this->app->singleton('symfony.transport', fn() => new SendmailTransport()); } /** diff --git a/src/Illuminate/Routing/RoutingServiceProvider.php b/src/Illuminate/Routing/RoutingServiceProvider.php index 9d1d078f9..9ef8da535 100755 --- a/src/Illuminate/Routing/RoutingServiceProvider.php +++ b/src/Illuminate/Routing/RoutingServiceProvider.php @@ -27,7 +27,7 @@ public function register() */ protected function registerRouter() { - $this->app['router'] = $this->app->share(function($app) + $this->app->singleton('router', function($app) { $router = new Router($app['events'], $app); @@ -50,7 +50,7 @@ protected function registerRouter() */ protected function registerUrlGenerator() { - $this->app['url'] = $this->app->share(function($app) + $this->app->singleton('url', function($app) { // The URL generator needs the route collection that exists on the router. // Keep in mind this is an object, so we're passing by references here @@ -71,7 +71,7 @@ protected function registerUrlGenerator() */ protected function registerRedirector() { - $this->app['redirect'] = $this->app->share(function($app) + $this->app->singleton('redirect', function($app) { $redirector = new Redirector($app['url']); @@ -94,7 +94,7 @@ protected function registerRedirector() */ protected function registerResponseFactory() { - $this->app[\Illuminate\Contracts\Routing\ResponseFactory::class] = $this->app->share(function($app) + $this->app->singleton(\Illuminate\Contracts\Routing\ResponseFactory::class, function($app) { return new ResponseFactory($app); }); From f63ca1206db851eb6e654b8582acda44239b381f Mon Sep 17 00:00:00 2001 From: agis Date: Fri, 18 Sep 2026 16:24:39 +0700 Subject: [PATCH 3/4] feat(container): swap Illuminate\Container for illuminate/container:^13 (task 4.1, SCC-1 window) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First SCC-1 core member cut over to a real v13 package. illuminate/container:^13 depends only on contracts (already ^13 from the seed phase), so it flips independently ahead of the support-gated remainder of the window. - composer.json: illuminate/container ^13 -> require, removed from replace. - Deleted fork src/Illuminate/Container/ tree (v13 package shadows it via the longer Illuminate\Container\ PSR-4 prefix; concrete classes now vendored). - Foundation\Application: BindingResolutionException import -> Contracts (v13 moved it there; docblock-only @throws, no runtime path). - tests/Container/ deleted (157 tests): these unit-test the container itself, now a vendored package tested upstream — the fork must not re-test a dependency. - tests/{Foundation,Mail,Exception}: bindShared()/share()/exception refs adapted. Application extends v13 Container with no signature break (make/bound/extend overrides compatible; verified via isolated class_exists probes). Fork suite green (1489, 0 fail; -157 from the removed container tests). composer.lock is gitignored. Prep landed earlier this branch: bindShared() sweep (69421972), share() sweep (f1fff797). Co-Authored-By: Claude Opus 4.8 (1M context) --- composer.json | 2 +- .../Container/BindingResolutionException.php | 3 - src/Illuminate/Container/BoundMethod.php | 247 --- .../Container/CircularDependencyException.php | 10 - src/Illuminate/Container/Container.php | 1556 ----------------- .../Container/ContainerExtendTest.php | 188 -- .../Container/ContextualBindingBuilder.php | 92 - .../Container/EntryNotFoundException.php | 8 - .../Container/RewindableGenerator.php | 61 - src/Illuminate/Container/composer.json | 25 - src/Illuminate/Foundation/Application.php | 2 +- tests/Container/ContainerCallTest.php | 295 ---- .../ContainerContextualBindingTest.php | 635 ------- tests/Container/ContainerExtendTest.php | 200 --- tests/Container/ContainerL4Test.php | 366 ---- tests/Container/ContainerNewTest.php | 690 -------- .../ContainerResolveNonInstantiableTest.php | 75 - tests/Container/ContainerTaggingTest.php | 105 -- tests/Container/ResolvingCallbackTest.php | 498 ------ tests/Container/RewindableGeneratorTest.php | 41 - tests/Exception/HandlerTest.php | 2 +- .../Foundation/FoundationApplicationTest.php | 8 +- tests/Mail/MailMailerTest.php | 2 +- 23 files changed, 8 insertions(+), 5103 deletions(-) delete mode 100644 src/Illuminate/Container/BindingResolutionException.php delete mode 100644 src/Illuminate/Container/BoundMethod.php delete mode 100644 src/Illuminate/Container/CircularDependencyException.php delete mode 100755 src/Illuminate/Container/Container.php delete mode 100644 src/Illuminate/Container/ContainerExtendTest.php delete mode 100644 src/Illuminate/Container/ContextualBindingBuilder.php delete mode 100644 src/Illuminate/Container/EntryNotFoundException.php delete mode 100644 src/Illuminate/Container/RewindableGenerator.php delete mode 100755 src/Illuminate/Container/composer.json delete mode 100644 tests/Container/ContainerCallTest.php delete mode 100644 tests/Container/ContainerContextualBindingTest.php delete mode 100644 tests/Container/ContainerExtendTest.php delete mode 100755 tests/Container/ContainerL4Test.php delete mode 100644 tests/Container/ContainerNewTest.php delete mode 100644 tests/Container/ContainerResolveNonInstantiableTest.php delete mode 100644 tests/Container/ContainerTaggingTest.php delete mode 100644 tests/Container/ResolvingCallbackTest.php delete mode 100644 tests/Container/RewindableGeneratorTest.php diff --git a/composer.json b/composer.json index 844595934..1b439753a 100755 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "filp/whoops": "~2.11", "illuminate/collections": "^13", "illuminate/conditionable": "^13", + "illuminate/container": "^13", "illuminate/contracts": "^13", "illuminate/macroable": "^13", "illuminate/reflection": "^13", @@ -46,7 +47,6 @@ "illuminate/cache": "self.version", "illuminate/config": "self.version", "illuminate/console": "self.version", - "illuminate/container": "self.version", "illuminate/cookie": "self.version", "illuminate/database": "self.version", "illuminate/encryption": "self.version", diff --git a/src/Illuminate/Container/BindingResolutionException.php b/src/Illuminate/Container/BindingResolutionException.php deleted file mode 100644 index 36975df20..000000000 --- a/src/Illuminate/Container/BindingResolutionException.php +++ /dev/null @@ -1,3 +0,0 @@ -make($segments[0]), $method], $parameters - ); - } - - /** - * Call a method that has been bound to the container. - * - * @param Container $container - * @param callable|string $callback - * @param mixed $default - * - * @return mixed - */ - protected static function callBoundMethod(Container $container, callable|string $callback, $default) - { - if (! is_array($callback)) { - return Util::unwrapIfClosure($default); - } - - // Here we need to turn the array callable into a Class@method string we can use to - // examine the container and see if there are any method bindings for this given - // method. If there are, we can call this method binding callback immediately. - $method = static::normalizeMethod($callback); - - if ($container->hasMethodBinding($method)) { - return $container->callMethodBinding($method, $callback[0]); - } - - // Diqo: - // This is where the array callback is executed. Note that the - // value that is used for execution is only $default, which is - // the closure that should haved "closure" in the callback and the - // required parameters. - // - // To further understand the mechanisme, see `call` on how it contrstruct - // the closure before calling this `callBoundMethod`. - // - // So, unwrapIfClosure just executed the $default closure. - return Util::unwrapIfClosure($default); - } - - /** - * Normalize the given callback into a Class@method string. - * - * @param callable $callback - * @return string - */ - protected static function normalizeMethod(callable $callback): string - { - $class = is_string($callback[0]) ? $callback[0] : get_class($callback[0]); - - return "{$class}@{$callback[1]}"; - } - - /** - * Get all dependencies for a given method. - * - * @param Container $container - * @param callable|string $callback - * @param array $parameters - * - * @return array - * - * @throws BindingResolutionException - * @throws ReflectionException - */ - protected static function getMethodDependencies( - Container $container, - callable|string $callback, - array $parameters = [] - ): array { - $dependencies = []; - - foreach (static::getCallReflector($callback)->getParameters() as $parameter) { - static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies); - } - - return array_merge($dependencies, array_values($parameters)); - } - - /** - * Get the proper reflection instance for the given callback. - * - * @param callable|string $callback - * @return \ReflectionFunctionAbstract - * - * @throws ReflectionException - */ - protected static function getCallReflector(callable|string $callback) - { - if (is_string($callback) && str_contains($callback, '::')) { - $callback = explode('::', $callback); - } elseif (is_object($callback) && ! $callback instanceof Closure) { - $callback = [$callback, '__invoke']; - } - - return is_array($callback) - ? new ReflectionMethod($callback[0], $callback[1]) - : new ReflectionFunction($callback); - } - - /** - * Get the dependency for the given call parameter. - * - * @param Container $container - * @param ReflectionParameter $parameter - * @param array $parameters - * @param array $dependencies - * - * @return void - * - * @throws BindingResolutionException - * @throws ReflectionException - */ - protected static function addDependencyForCallParameter( - Container $container, - ReflectionParameter $parameter, - array &$parameters, - array &$dependencies - ): void { - if (array_key_exists($paramName = $parameter->getName(), $parameters)) { - $dependencies[] = $parameters[$paramName]; - - unset($parameters[$paramName]); - } elseif (! is_null($className = Reflector::getParameterClassName($parameter))) { - if (array_key_exists($className, $parameters)) { - $dependencies[] = $parameters[$className]; - - unset($parameters[$className]); - } elseif ($parameter->isVariadic()) { - $variadicDependencies = $container->make($className); - - $dependencies = array_merge($dependencies, is_array($variadicDependencies) - ? $variadicDependencies - : [$variadicDependencies]); - } else { - $dependencies[] = $container->make($className); - } - } elseif ($parameter->isDefaultValueAvailable()) { - $dependencies[] = $parameter->getDefaultValue(); - } elseif (! $parameter->isOptional() && ! array_key_exists($paramName, $parameters)) { - $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}"; - - throw new BindingResolutionException($message); - } - } - - /** - * Determine if the given string is in Class@method syntax. - * - * @param mixed $callback - * @return bool - */ - protected static function isCallableWithAtSign($callback): bool - { - return is_string($callback) && str_contains($callback, '@'); - } -} diff --git a/src/Illuminate/Container/CircularDependencyException.php b/src/Illuminate/Container/CircularDependencyException.php deleted file mode 100644 index 9b00b3301..000000000 --- a/src/Illuminate/Container/CircularDependencyException.php +++ /dev/null @@ -1,10 +0,0 @@ -getAlias($c); - } - - return new ContextualBindingBuilder($this, $aliases); - } - - /** - * Add a contextual binding to the container. - * - * @param string $concrete - * @param string $abstract - * @param \Closure|string $implementation - * - * @return void - */ - public function addContextualBinding($concrete, $abstract, $implementation): void - { - $this->contextual[$concrete][$this->getAlias($abstract)] = $implementation; - } - - /** - * Determine if the given abstract type has been bound. - * - * @param string $abstract - * @return bool - */ - public function bound($abstract): bool - { - return isset($this->bindings[$abstract]) || - isset($this->instances[$abstract]) || - $this->isAlias($abstract); - } - - /** - * Determine if the container has a method binding. - * - * @param string $method - * @return bool - */ - public function hasMethodBinding($method): bool - { - return isset($this->methodBindings[$method]); - } - - /** - * Bind a callback to resolve with Container::call. - * - * @param array|string $method - * @param \Closure $callback - * @return void - */ - public function bindMethod($method, $callback): void - { - $this->methodBindings[$this->parseBindMethod($method)] = $callback; - } - - /** - * Get the method to be bound in class@method format. - * - * @param array|string $method - * @return string - */ - protected function parseBindMethod($method): string - { - if (is_array($method)) { - return $method[0].'@'.$method[1]; - } - - return $method; - } - - /** - * Get the method binding for the given method. - * - * @param string $method - * @param mixed $instance - * @return mixed - */ - public function callMethodBinding($method, $instance) - { - return call_user_func($this->methodBindings[$method], $instance, $this); - } - - /** - * {@inheritdoc} - * - * @return bool - */ - public function has(string $id): bool - { - return $this->bound($id); - } - - /** - * Determine if the given abstract type has been resolved. - * - * @param string $abstract - * @return bool - */ - public function resolved($abstract): bool - { - if ($this->isAlias($abstract)) { - $abstract = $this->getAlias($abstract); - } - - return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]); - } - - /** - * Determine if a given string is an alias. - * - * @param string $name - * @return bool - */ - public function isAlias($name): bool - { - return isset($this->aliases[$name]); - } - - /** - * Register a binding with the container. - * - * @param string|array $abstract - * @param $concrete - * @param bool $shared - * - * @return void - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function bind($abstract, $concrete = null, $shared = false): void - { - // If the given types are actually an array, we will assume an alias is being - // defined and will grab this "real" abstract class name and register this - // alias with the container so that it can be used as a shortcut for it. - if (is_array($abstract)) { - [$abstract, $alias] = $this->extractAlias($abstract); - - $this->alias($abstract, $alias); - } - - $this->dropStaleInstances($abstract); - - // If no concrete type was given, we will simply set the concrete type to the - // abstract type. This will allow concrete type to be registered as shared - // without being forced to state their classes in both of the parameter. - if (is_null($concrete)) { - $concrete = $abstract; - } - - // If the factory is not a Closure, it means it is just a class name which is - // is bound into this container to the abstract type and we will just wrap - // it up inside a Closure to make things more convenient when extending. - if ( ! $concrete instanceof Closure) { - if (! is_string($concrete)) { - throw new \TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null'); - } - - $concrete = $this->getClosure($abstract, $concrete); - } - - $this->bindings[$abstract] = compact('concrete', 'shared'); - - // If the abstract type was already resolved in this container we'll fire the - // rebound listener so that any objects which have already gotten resolved - // can have their copy of the object updated via the listener callbacks. - if ($this->resolved($abstract)) - { - $this->rebound($abstract); - } - } - - /** - * Get the Closure to be used when building a type. - * - * @param string $abstract - * @param string $concrete - * - * @return \Closure - */ - protected function getClosure(string $abstract, string $concrete): Closure - { - return function($c, $parameters = array()) use ($abstract, $concrete) { - $method = ($abstract === $concrete) ? 'build' : 'make'; - - return $c->$method($concrete, $parameters, false); - }; - } - - /** - * Register a binding if it hasn't already been registered. - * - * @param string $abstract - * @param \Closure|string|null $concrete - * @param bool $shared - * @return void - */ - public function bindIf($abstract, $concrete = null, $shared = false): void - { - if ( ! $this->bound($abstract)) { - $this->bind($abstract, $concrete, $shared); - } - } - - /** - * Register a shared binding in the container. - * - * @param string $abstract - * @param null $concrete - * - * @return void - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function singleton($abstract, $concrete = null): void - { - $this->bind($abstract, $concrete, true); - } - - /** - * Register a shared binding if it hasn't already been registered. - * - * @param string $abstract - * @param \Closure|string|null $concrete - * @return void - */ - public function singletonIf($abstract, $concrete = null): void - { - if (! $this->bound($abstract)) { - $this->singleton($abstract, $concrete); - } - } - - /** - * Register a scoped binding in the container. - * - * @param \Closure|string $abstract - * @param \Closure|string|null $concrete - * @return void - */ - public function scoped($abstract, $concrete = null): void - { - if (! in_array($abstract, $this->scopedInstances, true)) { - $this->scopedInstances[] = $abstract; - } - - $this->singleton($abstract, $concrete); - } - - /** - * Register a scoped binding if it hasn't already been registered. - * - * @param \Closure|string $abstract - * @param \Closure|string|null $concrete - * @return void - */ - public function scopedIf($abstract, $concrete = null): void - { - if (! $this->bound($abstract)) { - $this->scoped($abstract, $concrete); - } - } - - /** - * Wrap a Closure such that it is shared. - * - * @param \Closure $closure - * @return \Closure - */ - public function share(Closure $closure): Closure - { - return function($container) use ($closure) - { - // We'll simply declare a static variable within the Closures and if it has - // not been set we will execute the given Closures to resolve this value - // and return it back to these consumers of the method as an instance. - static $object; - - if (is_null($object)) - { - $object = $closure($container); - } - - return $object; - }; - } - - /** - * Bind a shared Closure into the container. - * - * @param string $abstract - * @param \Closure $closure - * @return void - */ - public function bindShared($abstract, Closure $closure): void - { - $this->bind($abstract, $this->share($closure), true); - } - - /** - * "Extend" an abstract type in the container. - * - * @param string $abstract - * @param \Closure $closure - * - * @return void - * - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function extend($abstract, Closure $closure): void - { - $abstract = $this->getAlias($abstract); - - if (isset($this->instances[$abstract])) { - $this->instances[$abstract] = $closure($this->instances[$abstract], $this); - - $this->rebound($abstract); - } else { - $this->extenders[$abstract][] = $closure; - - if ($this->resolved($abstract)) { - $this->rebound($abstract); - } - } - } - - /** - * Get an extender Closure for resolving a type. - * - * @deprecated - * @param string $abstract - * @param \Closure $closure - * @return \Closure - */ - protected function getExtender($abstract, Closure $closure): Closure - { - // To "extend" a binding, we will grab the old "resolver" Closure and pass it - // into a new one. The old resolver will be called first and the result is - // handed off to the "new" resolver, along with this container instance. - $resolver = $this->bindings[$abstract]['concrete']; - - return function($container) use ($resolver, $closure) - { - return $closure($resolver($container), $container); - }; - } - - /** - * Register an existing instance as shared in the container. - * - * @param string|array $abstract - * @param mixed $instance - * - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function instance($abstract, $instance) - { - // First, we will extract the alias from the abstract if it is an array so we - // are using the correct name when binding the type. If we get an alias it - // will be registered with the container so we can resolve it out later. - if (is_array($abstract)) - { - [$abstract, $alias] = $this->extractAlias($abstract); - - $this->alias($abstract, $alias); - } - - $this->removeAbstractAlias($abstract); - - unset($this->aliases[$abstract]); - - // We'll check to determine if this type has been bound before, and if it has - // we will fire the rebound callbacks registered with the container and it - // can be updated with consuming classes that have gotten resolved here. - $isBound = $this->bound($abstract); - - $this->instances[$abstract] = $instance; - - if ($isBound) { - $this->rebound($abstract); - } - - return $instance; - } - - /** - * Remove an alias from the contextual binding alias cache. - * - * @param string $searched - * @return void - */ - protected function removeAbstractAlias($searched): void - { - if (! isset($this->aliases[$searched])) { - return; - } - - foreach ($this->abstractAliases as $abstract => $aliases) { - foreach ($aliases as $index => $alias) { - if ($alias == $searched) { - unset($this->abstractAliases[$abstract][$index]); - } - } - } - } - - /** - * Assign a set of tags to a given binding. - * - * @param array|string $abstracts - * @param array|mixed ...$tags - * @return void - */ - public function tag($abstracts, $tags): void - { - $tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1); - - foreach ($tags as $tag) { - if (! isset($this->tags[$tag])) { - $this->tags[$tag] = []; - } - - foreach ((array) $abstracts as $abstract) { - $this->tags[$tag][] = $abstract; - } - } - } - - /** - * Resolve all of the bindings for a given tag. - * - * @param string $tag - */ - public function tagged($tag) - { - if (! isset($this->tags[$tag])) { - return []; - } - - return new RewindableGenerator(function () use ($tag) { - foreach ($this->tags[$tag] as $abstract) { - yield $this->make($abstract); - } - }, count($this->tags[$tag])); - } - - /** - * Alias a type to a shorter name. - * - * @param string $abstract - * @param string $alias - * @return void - */ - public function alias($abstract, $alias): void - { - if ($alias === $abstract) { - throw new LogicException("[{$abstract}] is aliased to itself."); - } - - $this->aliases[$alias] = $abstract; - - $this->abstractAliases[$abstract][] = $alias; - } - - /** - * Extract the type and alias from a given definition. - * - * @param array $definition - * @return array - */ - protected function extractAlias(array $definition): array - { - return array(key($definition), current($definition)); - } - - /** - * Bind a new callback to an abstract's rebind event. - * - * @param string $abstract - * @param \Closure $callback - * - * @return mixed - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function rebinding($abstract, Closure $callback) - { - $this->reboundCallbacks[$abstract][] = $callback; - - if ($this->bound($abstract)) { - return $this->make($abstract); - } - } - - /** - * Refresh an instance on the given target and method. - * - * @param string $abstract - * @param mixed $target - * @param string $method - * - * @return mixed - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function refresh($abstract, $target, $method) - { - return $this->rebinding($abstract, function($app, $instance) use ($target, $method) - { - $target->{$method}($instance); - }); - } - - /** - * Fire the "rebound" callbacks for the given abstract type. - * - * @param string $abstract - * - * @return void - * @throws BindingResolutionException - * @throws ReflectionException - */ - protected function rebound($abstract): void - { - $instance = $this->make($abstract); - - foreach ($this->getReboundCallbacks($abstract) as $callback) { - $callback($this, $instance); - } - } - - /** - * Get the rebound callbacks for a given type. - * - * @param string $abstract - * @return array - */ - protected function getReboundCallbacks($abstract): array - { - if (isset($this->reboundCallbacks[$abstract])) - { - return $this->reboundCallbacks[$abstract]; - } - - return array(); - } - - /** - * Wrap the given closure such that its dependencies will be injected when executed. - * - * @param \Closure $callback - * @param array $parameters - * @return \Closure - */ - public function wrap(Closure $callback, array $parameters = []): Closure - { - return function () use ($callback, $parameters) { - return $this->call($callback, $parameters); - }; - } - - /** - * Call the given Closure / class@method and inject its dependencies. - * - * @param callable|string $callback - * @param array $parameters - * @param null $defaultMethod - * - * @return mixed - * - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function call($callback, array $parameters = [], $defaultMethod = null) - { - return BoundMethod::call($this, $callback, $parameters, $defaultMethod); - } - - /** - * Get a closure to resolve the given type from the container. - * - * @param string $abstract - * - * @return \Closure - */ - public function factory($abstract): Closure - { - return function () use ($abstract) { - return $this->make($abstract); - }; - } - - /** - * An alias function name for make(). - * - * @param string|callable $abstract - * @param array $parameters - * - * @return mixed - * - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function makeWith($abstract, array $parameters = []) - { - return $this->make($abstract, $parameters); - } - - /** - * {@inheritdoc} - * - * @param string $id - * - * @return mixed - * @throws CircularDependencyException - * @throws EntryNotFoundException - */ - public function get(string $id) - { - try { - return $this->make($id); - } catch (Exception $e) { - if ($this->has($id) || $e instanceof CircularDependencyException) { - throw $e; - } - - throw new EntryNotFoundException($id, is_int($e->getCode()) ? $e->getCode() : 0, $e); - } - } - - /** - * Resolve the given type from the container. - * - * @param string|callable $abstract - * @param array $parameters - * @param bool $raiseEvents - * - * @return mixed - * @throws BindingResolutionException - * @throws \ReflectionException - */ - public function make($abstract, $parameters = array(), $raiseEvents = true) - { - $abstract = $this->getAlias($abstract); - - // First we'll fire any event handlers which handle the "before" resolving of - // specific types. This gives some hooks the chance to add various extends - // calls to change the resolution of objects that they're interested in. - if ($raiseEvents) { - $this->fireBeforeResolvingCallbacks($abstract, $parameters); - } - - $concrete = $this->getContextualConcrete($abstract); - - $needsContextualBuild = ! empty($parameters) || ! is_null($concrete); - - // If an instance of the type is currently being managed as a singleton we'll - // just return an existing instance instead of instantiating new instances - // so the developer can keep using the same objects instance every time. - if (isset($this->instances[$abstract]) && ! $needsContextualBuild) { - return $this->instances[$abstract]; - } - - if (is_null($concrete)) { - $concrete = $this->getConcrete($abstract); - } - - // We're ready to instantiate an instance of the concrete type registered for - // the binding. This will instantiate the types, as well as resolve any of - // its "nested" dependencies recursively until all have gotten resolved. - if ($this->isBuildable($concrete, $abstract)) { - $object = $this->build($concrete, $parameters); - } else { - $object = $this->make($concrete, $parameters); - } - - // If we defined any extenders for this type, we'll need to spin through them - // and apply them to the object being built. This allows for the extension - // of services, such as changing configuration or decorating the object. - foreach ($this->getExtenders($abstract) as $extender) { - $object = $extender($object, $this); - } - - // If the requested type is registered as a singleton we'll want to cache off - // the instances in "memory" so we can return it later without creating an - // entirely new instance of an object on each subsequent request for it. - if ($this->isShared($abstract) && ! $needsContextualBuild) { - $this->instances[$abstract] = $object; - } - - if ($raiseEvents) { - $this->fireResolvingCallbacks($abstract, $object); - } - - // Before returning, we will also set the resolved flag to "true". - // After that we will be ready to return back the fully constructed class instance. - $this->resolved[$abstract] = true; - - return $object; - } - - /** - * Get the contextual concrete binding for the given abstract. - * - * @param string|callable $abstract - * @return \Closure|string|array|null - */ - protected function getContextualConcrete($abstract) - { - if (! is_null($binding = $this->findInContextualBindings($abstract))) { - return $binding; - } - - // Next we need to see if a contextual binding might be bound under an alias of the - // given abstract type. So, we will need to check if any aliases exist with this - // type and then spin through them and check for contextual bindings on these. - if (empty($this->abstractAliases[$abstract])) { - return null; - } - - foreach ($this->abstractAliases[$abstract] as $alias) { - if (! is_null($binding = $this->findInContextualBindings($alias))) { - return $binding; - } - } - - return null; - } - - /** - * Find the concrete binding for the given abstract in the contextual binding array. - * - * @param string|callable $abstract - * @return \Closure|string|null - */ - protected function findInContextualBindings($abstract) - { - return $this->contextual[end($this->buildStack)][$abstract] ?? null; - } - - /** - * Get the extender callbacks for a given type. - * - * @param string $abstract - * @return array - */ - protected function getExtenders($abstract): array - { - return $this->extenders[$this->getAlias($abstract)] ?? []; - } - - /** - * Remove all of the extender callbacks for a given type. - * - * @param string $abstract - * @return void - */ - public function forgetExtenders($abstract): void - { - unset($this->extenders[$this->getAlias($abstract)]); - } - - /** - * Get the concrete type for a given abstract. - * - * @param string $abstract - * - * @return mixed $concrete - */ - protected function getConcrete(string $abstract) - { - // If we don't have a registered resolver or concrete for the type, we'll just - // assume each type is a concrete name and will attempt to resolve it as is - // since the container should be able to resolve concretes automatically. - if ( ! isset($this->bindings[$abstract])) - { - if ($this->missingLeadingSlash($abstract) && isset($this->bindings['\\'.$abstract])) - { - $abstract = '\\'.$abstract; - } - - return $abstract; - } - - return $this->bindings[$abstract]['concrete']; - } - - /** - * Determine if the given abstract has a leading slash. - * - * @param string $abstract - * - * @return bool - */ - protected function missingLeadingSlash(string $abstract): bool - { - return is_string($abstract) && strpos($abstract, '\\') !== 0; - } - - /** - * Instantiate a concrete instance of the given type. - * - * @param string|Closure $concrete - * @param array $parameters - * - * @return mixed - * - * @throws BindingResolutionException - * @throws \ReflectionException - */ - public function build($concrete, $parameters = array()) - { - // If the concrete type is actually a Closure, we will just execute it and - // hand back the results of the functions, which allows functions to be - // used as resolvers for more fine-tuned resolution of these objects. - if ($concrete instanceof Closure) { - return $concrete($this, $parameters); - } - - try { - $reflector = new ReflectionClass($concrete); - } catch (ReflectionException $e) { - throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e); - } - - // If the type is not instantiable, the developer is attempting to resolve - // an abstract type such as an Interface of Abstract Class and there is - // no binding registered for the abstractions so we need to bail out. - if ( ! $reflector->isInstantiable()) { - $this->notInstantiable($concrete); - } - - // Diqo: - // Why do we need to hold build stack? - // This is to suport variadic binding resolution. Please check - // \Illuminate\Container\Container::resolveVariadicClass - // - // The $concrete will be popped after it has been built or the container - // faced error in building it. - $this->buildStack[] = $concrete; - - $constructor = $reflector->getConstructor(); - - // If there are no constructors, that means there are no dependencies then - // we can just resolve the instances of the objects right away, without - // resolving any other types or dependencies out of these containers. - if (is_null($constructor)) { - array_pop($this->buildStack); - - return new $concrete; - } - - try { - $dependencies = $constructor->getParameters(); - - // Once we have all the constructor's parameters we can create each of the - // dependency instances and then use the reflection instances to make a - // new instance of this class, injecting the created dependencies in. - - $parameters = $this->keyParametersByArgument( - $dependencies, $parameters - ); - - $instances = $this->getDependencies( - $dependencies, $parameters - ); - } catch (BindingResolutionException $exception) { - array_pop($this->buildStack); - - throw $exception; - } - - array_pop($this->buildStack); - - return $reflector->newInstanceArgs($instances); - } - - /** - * Throw an exception that the concrete is not instantiable. - * - * @param string $concrete - * @return void - * - * @throws BindingResolutionException - */ - protected function notInstantiable($concrete): void - { - if (! empty($this->buildStack)) { - $previous = implode(', ', $this->buildStack); - - $message = "Target [$concrete] is not instantiable while building [$previous]."; - } else { - $message = "Target [$concrete] is not instantiable."; - } - - throw new BindingResolutionException($message); - } - - /** - * Resolve all of the dependencies from the ReflectionParameters. - * - * @param array $parameters - * @param array $primitives - * - * @return array - * @throws BindingResolutionException - * @throws ReflectionException - */ - protected function getDependencies(array $parameters, array $primitives = array()): array - { - $dependencies = []; - - foreach ($parameters as $parameter) - { - $dependency = Reflector::getParameterClassName($parameter); - - if (array_key_exists($parameter->name, $primitives)) { - // If the dependency has an override for this particular build we will use - // that instead as the value. Otherwise, we will continue with this run - // of resolutions and let reflection attempt to determine the result. - $dependencies[] = $primitives[$parameter->name]; - continue; - } - - if (is_null($dependency)) { - // If the class is null, it means the dependency is a string or some other - // primitive type which we can not resolve since it is not a class and - // we will just bomb out with an error since we have no-where to go. - $result = $this->resolveNonClass($parameter); - } else { - $result = $this->resolveClass($parameter); - } - - if ($parameter->isVariadic()) { - $dependencies = array_merge($dependencies, $result); - } else { - $dependencies[] = $result; - } - } - - return $dependencies; - } - - /** - * Resolve a non-class hinted dependency. - * - * @param \ReflectionParameter $parameter - * @return mixed - * - * @throws BindingResolutionException - */ - protected function resolveNonClass(ReflectionParameter $parameter) - { - if (!is_null($concrete = $this->getContextualConcrete('$' . $parameter->getName()))) { - return Util::unwrapIfClosure($concrete, $this); - } - - if ($parameter->isDefaultValueAvailable()) { - return $parameter->getDefaultValue(); - } - - $message = "Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}"; - - throw new BindingResolutionException($message); - } - - /** - * Resolve a class based dependency from the container. - * - * @param \ReflectionParameter $parameter - * - * @return mixed - * - * @throws BindingResolutionException - * @throws ReflectionException - */ - protected function resolveClass(ReflectionParameter $parameter) - { - try { - return $parameter->isVariadic() - ? $this->resolveVariadicClass($parameter) - : $this->make(Reflector::getParameterClassName($parameter)); - } - - // If we can not resolve the class instance, we will check to see if the value - // is optional, and if it is we will return the optional parameter value as - // the value of the dependency, similarly to how we do this with scalars. - catch (BindingResolutionException $e) - { - if ($parameter->isDefaultValueAvailable()) - { - return $parameter->getDefaultValue(); - } - - if ($parameter->isVariadic()) { - return []; - } - - throw $e; - } - } - - /** - * Resolve a class based variadic dependency from the container. - * - * @param \ReflectionParameter $parameter - * - * @return mixed - * @throws BindingResolutionException - * @throws ReflectionException - */ - protected function resolveVariadicClass(ReflectionParameter $parameter) - { - $className = Reflector::getParameterClassName($parameter); - - $abstract = $this->getAlias($className); - - if (!is_array($concrete = $this->getContextualConcrete($abstract))) { - return $this->make($className); - } - - return array_map(function ($abstract) { - return $this->make($abstract); - }, $concrete); - } - - /** - * If extra parameters are passed by numeric ID, rekey them by argument name. - * - * @param array $dependencies - * @param array $parameters - * @return array - */ - protected function keyParametersByArgument(array $dependencies, array $parameters): array - { - foreach ($parameters as $key => $value) - { - if (is_numeric($key)) - { - unset($parameters[$key]); - - $parameters[$dependencies[$key]->name] = $value; - } - } - - return $parameters; - } - - /** - * Register a new before resolving callback for all types. - * - * @param \Closure|string $abstract - * @param \Closure|null $callback - * @return void - */ - public function beforeResolving($abstract, ?Closure $callback = null) - { - if (is_string($abstract)) { - $abstract = $this->getAlias($abstract); - } - - if ($abstract instanceof Closure && is_null($callback)) { - $this->globalBeforeResolvingCallbacks[] = $abstract; - } else { - $this->beforeResolvingCallbacks[$abstract][] = $callback; - } - } - - /** - * Register a new resolving callback. - * - * @param string|callable $abstract - * @param \Closure $callback - * @return void - */ - public function resolving($abstract, ?Closure $callback = null): void - { - if (is_string($abstract)) { - $abstract = $this->getAlias($abstract); - } - - if (is_null($callback) && $abstract instanceof Closure) { - // This is global callback, where it will be called - // when the container resolves any type - $this->globalResolvingCallbacks[] = $abstract; - } else { - // Call the callback when the container resolves $abstract - $this->resolvingCallbacks[$abstract][] = $callback; - } - } - - /** - * Register a new after resolving callback for all types. - * - * @param \Closure|string $abstract - * @param \Closure|null $callback - * @return void - */ - public function afterResolving($abstract, ?Closure $callback = null) - { - if (is_string($abstract)) { - $abstract = $this->getAlias($abstract); - } - - if ($abstract instanceof Closure && is_null($callback)) { - $this->globalAfterResolvingCallbacks[] = $abstract; - } else { - $this->afterResolvingCallbacks[$abstract][] = $callback; - } - } - - /** - * Register a new resolving callback for all types. - * - * @param \Closure $callback - * @return void - */ - public function resolvingAny(Closure $callback): void - { - $this->globalResolvingCallbacks[] = $callback; - } - - /** - * Fire all of the before resolving callbacks. - * - * @param string $abstract - * @param array $parameters - * @return void - */ - protected function fireBeforeResolvingCallbacks($abstract, $parameters = []): void - { - $this->fireBeforeCallbackArray($abstract, $parameters, $this->globalBeforeResolvingCallbacks); - - foreach ($this->beforeResolvingCallbacks as $type => $callbacks) { - if ($type === $abstract || is_subclass_of($abstract, $type)) { - $this->fireBeforeCallbackArray($abstract, $parameters, $callbacks); - } - } - } - - /** - * Fire an array of callbacks with an object. - * - * @param string $abstract - * @param array $parameters - * @param array $callbacks - * @return void - */ - protected function fireBeforeCallbackArray($abstract, $parameters, array $callbacks): void - { - foreach ($callbacks as $callback) { - $callback($abstract, $parameters, $this); - } - } - - /** - * Fire all of the resolving callbacks. - * - * @param string $abstract - * @param mixed $object - * @return void - */ - protected function fireResolvingCallbacks($abstract, $object): void - { - $this->fireCallbackArray($object, $this->globalResolvingCallbacks); - - $this->fireCallbackArray( - $object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks) - ); - - $this->fireAfterResolvingCallbacks($abstract, $object); - } - - /** - * Fire all of the after resolving callbacks. - * - * @param string $abstract - * @param mixed $object - * @return void - */ - protected function fireAfterResolvingCallbacks($abstract, $object): void - { - $this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks); - - $this->fireCallbackArray( - $object, $this->getCallbacksForType($abstract, $object, $this->afterResolvingCallbacks) - ); - } - - /** - * Get all callbacks for a given type. - * - * @param string $abstract - * @param object $object - * @param array $callbacksPerType - * @return array - */ - protected function getCallbacksForType($abstract, $object, array $callbacksPerType): array - { - $results = []; - - foreach ($callbacksPerType as $type => $callbacks) { - if ($type === $abstract || $object instanceof $type) { - $results = array_merge($results, $callbacks); - } - } - - return $results; - } - - /** - * Fire an array of callbacks with an object. - * - * @param mixed $object - * @param array $callbacks - */ - protected function fireCallbackArray($object, array $callbacks): void - { - foreach ($callbacks as $callback) { - $callback($object, $this); - } - } - - /** - * Determine if a given type is shared. - * - * @param string $abstract - * - * @return bool - */ - public function isShared(string $abstract): bool - { - return isset($this->instances[$abstract]) || - (isset($this->bindings[$abstract]['shared']) && - $this->bindings[$abstract]['shared'] === true); - } - - /** - * Determine if the given concrete is buildable. - * - * @param mixed $concrete - * @param string $abstract - * @return bool - */ - protected function isBuildable($concrete, $abstract): bool - { - return $concrete === $abstract || $concrete instanceof Closure; - } - - /** - * Get the alias for an abstract if available. - * - * @param string $abstract - * - * @return string - */ - public function getAlias(string $abstract): string - { - return isset($this->aliases[$abstract]) - ? $this->getAlias($this->aliases[$abstract]) - : $abstract; - } - - /** - * Get the container's bindings. - * - * @return array - */ - public function getBindings(): array - { - return $this->bindings; - } - - /** - * Drop all of the stale instances and aliases. - * - * @param string $abstract - * @return void - */ - protected function dropStaleInstances($abstract): void - { - unset($this->instances[$abstract], $this->aliases[$abstract]); - } - - /** - * Remove a resolved instance from the instance cache. - * - * @param string $abstract - * @return void - */ - public function forgetInstance($abstract): void - { - unset($this->instances[$abstract]); - } - - /** - * Clear all of the instances from the container. - * - * @return void - */ - public function forgetInstances(): void - { - $this->instances = array(); - } - - /** - * Flush the container of all bindings and resolved instances. - * - * @return void - */ - public function flush(): void - { - $this->aliases = []; - $this->resolved = []; - $this->bindings = []; - $this->instances = []; - $this->abstractAliases = []; - } - - /** - * Determine if a given offset exists. - * - * @param string $key - * @return bool - */ - public function offsetExists($key): bool - { - return $this->bound($key); - } - - /** - * Get the value at a given offset. - * - * @param string $key - * - * @return mixed - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function offsetGet($key): mixed - { - return $this->make($key); - } - - /** - * Set the value at a given offset. - * - * @param string $key - * @param mixed $value - * - * @return void - * @throws BindingResolutionException - * @throws ReflectionException - */ - public function offsetSet($key, $value): void - { - // If the value is not a Closure, we will make it one. This simply gives - // more "drop-in" replacement functionality for the Pimple which this - // container's simplest functions are base modeled and built after. - if ( ! $value instanceof Closure) - { - $value = function() use ($value) - { - return $value; - }; - } - - $this->bind($key, $value); - } - - /** - * Unset the value at a given offset. - * - * @param string $key - * @return void - */ - public function offsetUnset($key): void - { - unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]); - } - - /** - * Dynamically access container services. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - return $this[$key]; - } - - /** - * Dynamically set container services. - * - * @param string $key - * @param mixed $value - * @return void - */ - public function __set($key, $value) - { - $this[$key] = $value; - } - -} diff --git a/src/Illuminate/Container/ContainerExtendTest.php b/src/Illuminate/Container/ContainerExtendTest.php deleted file mode 100644 index fd8ff2038..000000000 --- a/src/Illuminate/Container/ContainerExtendTest.php +++ /dev/null @@ -1,188 +0,0 @@ -extend('foo', function ($old, $container) { - return $old.'bar'; - }); - - $this->assertSame('foobar', $container->make('foo')); - - $container = new Container; - - $container->singleton('foo', function () { - return (object) ['name' => 'taylor']; - }); - $container->extend('foo', function ($old, $container) { - $old->age = 26; - - return $old; - }); - - $result = $container->make('foo'); - - $this->assertSame('taylor', $result->name); - $this->assertEquals(26, $result->age); - $this->assertSame($result, $container->make('foo')); - } - - public function testExtendInstancesArePreserved(): void - { - $container = new Container; - $container->bind('foo', function () { - $obj = new stdClass; - $obj->foo = 'bar'; - - return $obj; - }); - - $obj = new stdClass; - $obj->foo = 'foo'; - $container->instance('foo', $obj); - $container->extend('foo', function ($obj, $container) { - $obj->bar = 'baz'; - - return $obj; - }); - $container->extend('foo', function ($obj, $container) { - $obj->baz = 'foo'; - - return $obj; - }); - - $this->assertSame('foo', $container->make('foo')->foo); - $this->assertSame('baz', $container->make('foo')->bar); - $this->assertSame('foo', $container->make('foo')->baz); - } - - public function testExtendIsLazyInitialized(): void - { - ContainerLazyExtendStub::$initialized = false; - - $container = new Container; - $container->bind(ContainerLazyExtendStub::class); - $container->extend(ContainerLazyExtendStub::class, function ($obj, $container) { - $obj->init(); - - return $obj; - }); - $this->assertFalse(ContainerLazyExtendStub::$initialized); - $container->make(ContainerLazyExtendStub::class); - $this->assertTrue(ContainerLazyExtendStub::$initialized); - } - - public function testExtendInstanceRebindingCallback(): void - { - $_SERVER['_test_rebind'] = false; - - $container = new Container; - $container->rebinding('foo', function () { - $_SERVER['_test_rebind'] = true; - }); - - $obj = new stdClass; - $container->instance('foo', $obj); - - $container->extend('foo', function ($obj, $container) { - return $obj; - }); - - $this->assertTrue($_SERVER['_test_rebind']); - } - - public function testExtendBindRebindingCallback(): void - { - $_SERVER['_test_rebind'] = false; - - $container = new Container; - $container->rebinding('foo', function () { - $_SERVER['_test_rebind'] = true; - }); - $container->bind('foo', function () { - return new stdClass; - }); - - $this->assertFalse($_SERVER['_test_rebind']); - - $container->make('foo'); - - $container->extend('foo', function ($obj, $container) { - return $obj; - }); - - $this->assertTrue($_SERVER['_test_rebind']); - } - - public function testExtensionWorksOnAliasedBindings(): void - { - $container = new Container; - $container->singleton('something', function () { - return 'some value'; - }); - $container->alias('something', 'something-alias'); - $container->extend('something-alias', function ($value) { - return $value.' extended'; - }); - - $this->assertSame('some value extended', $container->make('something')); - } - - public function testMultipleExtends(): void - { - $container = new Container; - $container['foo'] = 'foo'; - $container->extend('foo', function ($old, $container) { - return $old.'bar'; - }); - $container->extend('foo', function ($old, $container) { - return $old.'baz'; - }); - - $this->assertSame('foobarbaz', $container->make('foo')); - } - - public function testUnsetExtend(): void - { - $container = new Container; - $container->bind('foo', function () { - $obj = new stdClass; - $obj->foo = 'bar'; - - return $obj; - }); - - $container->extend('foo', function ($obj, $container) { - $obj->bar = 'baz'; - - return $obj; - }); - - unset($container['foo']); - $container->forgetExtenders('foo'); - - $container->bind('foo', function () { - return 'foo'; - }); - - $this->assertSame('foo', $container->make('foo')); - } -} - -class ContainerLazyExtendStub -{ - public static $initialized = false; - - public function init(): void - { - static::$initialized = true; - } -} diff --git a/src/Illuminate/Container/ContextualBindingBuilder.php b/src/Illuminate/Container/ContextualBindingBuilder.php deleted file mode 100644 index b5995b62d..000000000 --- a/src/Illuminate/Container/ContextualBindingBuilder.php +++ /dev/null @@ -1,92 +0,0 @@ -concrete = $concrete; - $this->container = $container; - } - - /** - * Define the abstract target that depends on the context. - * - * @param string $abstract - * - * @return ContextualBindingBuilder - */ - public function needs(string $abstract): ContextualBindingBuilder - { - $this->needs = $abstract; - - return $this; - } - - /** - * Define the implementation for the contextual binding. - * - * @param \Closure|string|array $implementation - * @return void - */ - public function give($implementation): void - { - foreach (Arr::wrap($this->concrete) as $concrete) { - $this->container->addContextualBinding($concrete, $this->needs, $implementation); - } - } - - /** - * Define tagged services to be used as the implementation for the contextual binding. - * - * @param string $tag - * @return void - */ - public function giveTagged($tag): void - { - $this->give(function ($container) use ($tag) { - $taggedServices = $container->tagged($tag); - - return is_array($taggedServices) ? $taggedServices : iterator_to_array($taggedServices); - }); - } - - /** - * Specify the configuration item to bind as a primitive. - * - * @param string $key - * @param mixed $default - * @return void - */ - public function giveConfig($key, $default = null): void - { - $this->give(fn ($container) => $container['config']->get($key, $default)); - } -} \ No newline at end of file diff --git a/src/Illuminate/Container/EntryNotFoundException.php b/src/Illuminate/Container/EntryNotFoundException.php deleted file mode 100644 index bb2ef2ade..000000000 --- a/src/Illuminate/Container/EntryNotFoundException.php +++ /dev/null @@ -1,8 +0,0 @@ -count = $count; - $this->generator = $generator; - } - - /** - * Get an iterator from the generator. - * - * @return \Traversable - */ - public function getIterator(): Traversable - { - return ($this->generator)(); - } - - /** - * Get the total number of tagged services. - * - * @return int - */ - public function count(): int - { - if (is_callable($count = $this->count)) { - $this->count = $count(); - } - - return $this->count; - } -} diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json deleted file mode 100755 index a2445f183..000000000 --- a/src/Illuminate/Container/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "illuminate/container", - "license": "MIT", - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "require": { - "php": ">=5.4.0" - }, - "autoload": { - "psr-0": { - "Illuminate\\Container": "" - } - }, - "target-dir": "Illuminate/Container", - "extra": { - "branch-alias": { - "dev-master": "4.2-dev" - } - }, - "minimum-stability": "dev" -} diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index e461fe620..6e7796b31 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -2,7 +2,7 @@ use Closure; use Illuminate\Support\Arr; -use Illuminate\Container\BindingResolutionException; +use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Foundation\Http\MiddlewareBuilder; use ReflectionException; use Illuminate\Http\Request; diff --git a/tests/Container/ContainerCallTest.php b/tests/Container/ContainerCallTest.php deleted file mode 100644 index 41fe88f3d..000000000 --- a/tests/Container/ContainerCallTest.php +++ /dev/null @@ -1,295 +0,0 @@ -expectException(Error::class); - $this->expectExceptionMessage('Call to undefined function ContainerTestCallStub()'); - - $container = new Container; - $container->call('ContainerTestCallStub'); - } - - public function testCallWithAtSignBasedClassReferences(): void - { - $container = new Container; - $result = $container->call(ContainerTestCallStub::class.'@work', ['foo', 'bar']); - $this->assertEquals(['foo', 'bar'], $result); - - $container = new Container; - $result = $container->call(ContainerTestCallStub::class.'@inject'); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('taylor', $result[1]); - - $container = new Container; - $result = $container->call(ContainerTestCallStub::class.'@inject', ['default' => 'foo']); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('foo', $result[1]); - - $container = new Container; - $result = $container->call(ContainerTestCallStub::class, ['foo', 'bar'], 'work'); - $this->assertEquals(['foo', 'bar'], $result); - } - - public function testCallWithCallableArray(): void - { - $container = new Container; - $stub = new ContainerTestCallStub; - $result = $container->call([$stub, 'work'], ['foo', 'bar']); - $this->assertEquals(['foo', 'bar'], $result); - } - - public function testCallWithStaticMethodNameString(): void - { - $container = new Container; - $result = $container->call('Illuminate\Tests\Container\ContainerStaticMethodStub::inject'); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('taylor', $result[1]); - } - - public function testCallWithGlobalMethodName(): void - { - $container = new Container; - $result = $container->call('Illuminate\Tests\Container\containerTestInject'); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('taylor', $result[1]); - } - - public function testCallWithBoundMethod(): void - { - $container = new Container; - $container->bindMethod(ContainerTestCallStub::class.'@unresolvable', function ($stub) { - return $stub->unresolvable('foo', 'bar'); - }); - $result = $container->call(ContainerTestCallStub::class.'@unresolvable'); - $this->assertEquals(['foo', 'bar'], $result); - - $container = new Container; - $container->bindMethod(ContainerTestCallStub::class.'@unresolvable', function ($stub) { - return $stub->unresolvable('foo', 'bar'); - }); - $result = $container->call([new ContainerTestCallStub, 'unresolvable']); - $this->assertEquals(['foo', 'bar'], $result); - - $container = new Container; - $result = $container->call([new ContainerTestCallStub, 'inject'], ['_stub' => 'foo', 'default' => 'bar']); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('bar', $result[1]); - - $container = new Container; - $result = $container->call([new ContainerTestCallStub, 'inject'], ['_stub' => 'foo']); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('taylor', $result[1]); - } - - public function testBindMethodAcceptsAnArray(): void - { - $container = new Container; - $container->bindMethod([ContainerTestCallStub::class, 'unresolvable'], function ($stub) { - return $stub->unresolvable('foo', 'bar'); - }); - $result = $container->call(ContainerTestCallStub::class.'@unresolvable'); - $this->assertEquals(['foo', 'bar'], $result); - - $container = new Container; - $container->bindMethod([ContainerTestCallStub::class, 'unresolvable'], function ($stub) { - return $stub->unresolvable('foo', 'bar'); - }); - $result = $container->call([new ContainerTestCallStub, 'unresolvable']); - $this->assertEquals(['foo', 'bar'], $result); - } - - public function testClosureCallWithInjectedDependency(): void - { - $container = new Container; - $container->call(function (ContainerCallConcreteStub $stub) { - // - }, ['foo' => 'bar']); - - $container->call(function (ContainerCallConcreteStub $stub) { - // - }, ['foo' => 'bar', 'stub' => new ContainerCallConcreteStub]); - } - - public function testCallWithDependencies(): void - { - $container = new Container; - $result = $container->call(function (stdClass $foo, $bar = []) { - return func_get_args(); - }); - - $this->assertInstanceOf(stdClass::class, $result[0]); - $this->assertEquals([], $result[1]); - - $result = $container->call(function (stdClass $foo, $bar = []) { - return func_get_args(); - }, ['bar' => 'taylor']); - - $this->assertInstanceOf(stdClass::class, $result[0]); - $this->assertSame('taylor', $result[1]); - - $stub = new ContainerCallConcreteStub; - $result = $container->call(function (stdClass $foo, ContainerCallConcreteStub $bar) { - return func_get_args(); - }, [ContainerCallConcreteStub::class => $stub]); - - $this->assertInstanceOf(stdClass::class, $result[0]); - $this->assertSame($stub, $result[1]); - - /* - * Wrap a function... - */ - $result = $container->wrap(function (stdClass $foo, $bar = []) { - return func_get_args(); - }, ['bar' => 'taylor']); - - $this->assertInstanceOf(Closure::class, $result); - $result = $result(); - - $this->assertInstanceOf(stdClass::class, $result[0]); - $this->assertSame('taylor', $result[1]); - } - - public function testCallWithVariadicDependency(): void - { - $stub1 = new ContainerCallConcreteStub; - $stub2 = new ContainerCallConcreteStub; - - $container = new Container; - $container->bind(ContainerCallConcreteStub::class, function () use ($stub1, $stub2) { - return [ - $stub1, - $stub2, - ]; - }); - - $result = $container->call(function (stdClass $foo, ContainerCallConcreteStub ...$bar) { - return func_get_args(); - }); - - $this->assertInstanceOf(stdClass::class, $result[0]); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[1]); - $this->assertSame($stub1, $result[1]); - $this->assertSame($stub2, $result[2]); - } - - public function testCallWithCallableObject(): void - { - $container = new Container; - $callable = new ContainerCallCallableStub; - $result = $container->call($callable); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('jeffrey', $result[1]); - } - - public function testCallWithCallableClassString(): void - { - $container = new Container; - $result = $container->call(ContainerCallCallableClassStringStub::class); - $this->assertInstanceOf(ContainerCallConcreteStub::class, $result[0]); - $this->assertSame('jeffrey', $result[1]); - $this->assertInstanceOf(ContainerTestCallStub::class, $result[2]); - } - - public function testCallWithoutRequiredParamsThrowsException(): void - { - $this->expectException(BindingResolutionException::class); - $this->expectExceptionMessage('Unable to resolve dependency [Parameter #0 [ $foo ]] in class Illuminate\Tests\Container\ContainerTestCallStub'); - - $container = new Container; - $container->call(ContainerTestCallStub::class.'@unresolvable'); - } - - public function testCallWithUnnamedParametersThrowsException(): void - { - $this->expectException(BindingResolutionException::class); - $this->expectExceptionMessage('Unable to resolve dependency [Parameter #0 [ $foo ]] in class Illuminate\Tests\Container\ContainerTestCallStub'); - - $container = new Container; - $container->call([new ContainerTestCallStub, 'unresolvable'], ['foo', 'bar']); - } - - public function testCallWithoutRequiredParamsOnClosureThrowsException(): void - { - $this->expectException(BindingResolutionException::class); - $this->expectExceptionMessage('Unable to resolve dependency [Parameter #0 [ $foo ]] in class Illuminate\Tests\Container\ContainerCallTest'); - - $container = new Container; - $container->call(function ($foo, $bar = 'default') { - return $foo; - }); - } -} - -class ContainerTestCallStub -{ - public function work(): array - { - return func_get_args(); - } - - public function inject(ContainerCallConcreteStub $stub, $default = 'taylor'): array - { - return func_get_args(); - } - - public function unresolvable($foo, $bar): array - { - return func_get_args(); - } -} - -class ContainerCallConcreteStub -{ - // -} - -function containerTestInject(ContainerCallConcreteStub $stub, $default = 'taylor') -{ - return func_get_args(); -} - -class ContainerStaticMethodStub -{ - public static function inject(ContainerCallConcreteStub $stub, $default = 'taylor'): array - { - return func_get_args(); - } -} - -class ContainerCallCallableStub -{ - public function __invoke(ContainerCallConcreteStub $stub, $default = 'jeffrey') - { - return func_get_args(); - } -} - -class ContainerCallCallableClassStringStub -{ - public $stub; - - public $default; - - public function __construct(ContainerCallConcreteStub $stub, $default = 'jeffrey') - { - $this->stub = $stub; - $this->default = $default; - } - - public function __invoke(ContainerTestCallStub $dependency) - { - return [$this->stub, $this->default, $dependency]; - } -} \ No newline at end of file diff --git a/tests/Container/ContainerContextualBindingTest.php b/tests/Container/ContainerContextualBindingTest.php deleted file mode 100644 index bba576471..000000000 --- a/tests/Container/ContainerContextualBindingTest.php +++ /dev/null @@ -1,635 +0,0 @@ -bind(IContainerContextContractStub::class, ContainerContextImplementationStub::class); - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStub::class); - $container->when(ContainerTestContextInjectTwo::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $one = $container->make(ContainerTestContextInjectOne::class); - $two = $container->make(ContainerTestContextInjectTwo::class); - - $this->assertInstanceOf(ContainerContextImplementationStub::class, $one->impl); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $two->impl); - - /* - * Test With Closures - */ - $container = new Container; - - $container->bind(IContainerContextContractStub::class, ContainerContextImplementationStub::class); - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStub::class); - $container->when(ContainerTestContextInjectTwo::class)->needs(IContainerContextContractStub::class)->give(function ($container) { - return $container->make(ContainerContextImplementationStubTwo::class); - }); - - $one = $container->make(ContainerTestContextInjectOne::class); - $two = $container->make(ContainerTestContextInjectTwo::class); - - $this->assertInstanceOf(ContainerContextImplementationStub::class, $one->impl); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $two->impl); - } - - public function testContextualBindingWorksForExistingInstancedBindings(): void - { - $container = new Container; - - $container->instance(IContainerContextContractStub::class, new ContainerContextImplementationStub); - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $container->make(ContainerTestContextInjectOne::class)->impl); - } - - public function testContextualBindingWorksForNewlyInstancedBindings(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $container->instance(IContainerContextContractStub::class, new ContainerContextImplementationStub); - - $this->assertInstanceOf( - ContainerContextImplementationStubTwo::class, - $container->make(ContainerTestContextInjectOne::class)->impl - ); - } - - public function testContextualBindingWorksOnExistingAliasedInstances(): void - { - $container = new Container; - - $container->instance('stub', new ContainerContextImplementationStub); - $container->alias('stub', IContainerContextContractStub::class); - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $this->assertInstanceOf( - ContainerContextImplementationStubTwo::class, - $container->make(ContainerTestContextInjectOne::class)->impl - ); - } - - public function testContextualBindingWorksOnNewAliasedInstances(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $container->instance('stub', new ContainerContextImplementationStub); - $container->alias('stub', IContainerContextContractStub::class); - - $this->assertInstanceOf( - ContainerContextImplementationStubTwo::class, - $container->make(ContainerTestContextInjectOne::class)->impl - ); - } - - public function testContextualBindingWorksOnNewAliasedBindings(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $container->bind('stub', ContainerContextImplementationStub::class); - $container->alias('stub', IContainerContextContractStub::class); - - $this->assertInstanceOf( - ContainerContextImplementationStubTwo::class, - $container->make(ContainerTestContextInjectOne::class)->impl - ); - } - - public function testContextualBindingWorksForMultipleClasses(): void - { - $container = new Container; - - $container->bind(IContainerContextContractStub::class, ContainerContextImplementationStub::class); - - $container->when([ContainerTestContextInjectTwo::class, ContainerTestContextInjectThree::class])->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $this->assertInstanceOf( - ContainerContextImplementationStub::class, - $container->make(ContainerTestContextInjectOne::class)->impl - ); - - $this->assertInstanceOf( - ContainerContextImplementationStubTwo::class, - $container->make(ContainerTestContextInjectTwo::class)->impl - ); - - $this->assertInstanceOf( - ContainerContextImplementationStubTwo::class, - $container->make(ContainerTestContextInjectThree::class)->impl - ); - } - - public function testContextualBindingDoesntOverrideNonContextualResolution(): void - { - $container = new Container; - - $container->instance('stub', new ContainerContextImplementationStub); - $container->alias('stub', IContainerContextContractStub::class); - - $container->when(ContainerTestContextInjectTwo::class)->needs(IContainerContextContractStub::class)->give(ContainerContextImplementationStubTwo::class); - - $this->assertInstanceOf( - ContainerContextImplementationStubTwo::class, - $container->make(ContainerTestContextInjectTwo::class)->impl - ); - - $this->assertInstanceOf( - ContainerContextImplementationStub::class, - $container->make(ContainerTestContextInjectOne::class)->impl - ); - } - - public function testContextuallyBoundInstancesAreNotUnnecessarilyRecreated(): void - { - ContainerTestContextInjectInstantiations::$instantiations = 0; - - $container = new Container; - - $container->instance(IContainerContextContractStub::class, new ContainerContextImplementationStub); - $container->instance(ContainerTestContextInjectInstantiations::class, new ContainerTestContextInjectInstantiations); - - $this->assertEquals(1, ContainerTestContextInjectInstantiations::$instantiations); - - $container->when(ContainerTestContextInjectOne::class)->needs(IContainerContextContractStub::class)->give(ContainerTestContextInjectInstantiations::class); - - $container->make(ContainerTestContextInjectOne::class); - $container->make(ContainerTestContextInjectOne::class); - $container->make(ContainerTestContextInjectOne::class); - $container->make(ContainerTestContextInjectOne::class); - - $this->assertEquals(1, ContainerTestContextInjectInstantiations::$instantiations); - } - - public function testContainerCanInjectSimpleVariable(): void - { - $container = new Container; - $container->when(ContainerInjectVariableStub::class)->needs('$something')->give(100); - $instance = $container->make(ContainerInjectVariableStub::class); - $this->assertEquals(100, $instance->something); - - $container = new Container; - $container->when(ContainerInjectVariableStub::class)->needs('$something')->give(function ($container) { - return $container->make(ContainerContextualConcreteStub::class); - }); - $instance = $container->make(ContainerInjectVariableStub::class); - $this->assertInstanceOf(ContainerContextualConcreteStub::class, $instance->something); - } - - public function testContextualBindingWorksWithAliasedTargets(): void - { - $container = new Container; - - $container->bind(IContainerContextContractStub::class, ContainerContextImplementationStub::class); - $container->alias(IContainerContextContractStub::class, 'interface-stub'); - - $container->alias(ContainerContextImplementationStub::class, 'stub-1'); - - $container->when(ContainerTestContextInjectOne::class)->needs('interface-stub')->give('stub-1'); - $container->when(ContainerTestContextInjectTwo::class)->needs('interface-stub')->give(ContainerContextImplementationStubTwo::class); - - $one = $container->make(ContainerTestContextInjectOne::class); - $two = $container->make(ContainerTestContextInjectTwo::class); - - $this->assertInstanceOf(ContainerContextImplementationStub::class, $one->impl); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $two->impl); - } - - public function testContextualBindingWorksForNestedOptionalDependencies(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectTwoInstances::class)->needs(ContainerTestContextInjectTwo::class)->give(function () { - return new ContainerTestContextInjectTwo(new ContainerContextImplementationStubTwo); - }); - - $resolvedInstance = $container->make(ContainerTestContextInjectTwoInstances::class); - $this->assertInstanceOf( - ContainerTestContextWithOptionalInnerDependency::class, - $resolvedInstance->implOne - ); - $this->assertNull($resolvedInstance->implOne->inner); - - $this->assertInstanceOf( - ContainerTestContextInjectTwo::class, - $resolvedInstance->implTwo - ); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $resolvedInstance->implTwo->impl); - } - - public function testContextualBindingWorksForVariadicDependencies(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectVariadic::class)->needs(IContainerContextContractStub::class)->give(function ($c) { - return [ - $c->make(ContainerContextImplementationStub::class), - $c->make(ContainerContextImplementationStubTwo::class), - ]; - }); - - $resolvedInstance = $container->make(ContainerTestContextInjectVariadic::class); - - $this->assertCount(2, $resolvedInstance->stubs); - $this->assertInstanceOf(ContainerContextImplementationStub::class, $resolvedInstance->stubs[0]); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $resolvedInstance->stubs[1]); - } - - public function testContextualBindingWorksForVariadicDependenciesWithNothingBound(): void - { - $container = new Container; - - $resolvedInstance = $container->make(ContainerTestContextInjectVariadic::class); - - $this->assertCount(0, $resolvedInstance->stubs); - } - - public function testContextualBindingWorksForVariadicAfterNonVariadicDependencies(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectVariadicAfterNonVariadic::class)->needs(IContainerContextContractStub::class)->give(function ($c) { - return [ - $c->make(ContainerContextImplementationStub::class), - $c->make(ContainerContextImplementationStubTwo::class), - ]; - }); - - $resolvedInstance = $container->make(ContainerTestContextInjectVariadicAfterNonVariadic::class); - - $this->assertCount(2, $resolvedInstance->stubs); - $this->assertInstanceOf(ContainerContextImplementationStub::class, $resolvedInstance->stubs[0]); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $resolvedInstance->stubs[1]); - } - - public function testContextualBindingWorksForVariadicAfterNonVariadicDependenciesWithNothingBound(): void - { - $container = new Container; - - $resolvedInstance = $container->make(ContainerTestContextInjectVariadicAfterNonVariadic::class); - - $this->assertCount(0, $resolvedInstance->stubs); - } - - public function testContextualBindingWorksForVariadicDependenciesWithoutFactory(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectVariadic::class)->needs(IContainerContextContractStub::class)->give([ - ContainerContextImplementationStub::class, - ContainerContextImplementationStubTwo::class, - ]); - - $resolvedInstance = $container->make(ContainerTestContextInjectVariadic::class); - - $this->assertCount(2, $resolvedInstance->stubs); - $this->assertInstanceOf(ContainerContextImplementationStub::class, $resolvedInstance->stubs[0]); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $resolvedInstance->stubs[1]); - } - - public function testContextualBindingGivesTagsForArrayWithNoTagsDefined(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectArray::class)->needs('$stubs')->giveTagged('stub'); - - $resolvedInstance = $container->make(ContainerTestContextInjectArray::class); - - $this->assertCount(0, $resolvedInstance->stubs); - } - - public function testContextualBindingGivesTagsForVariadicWithNoTagsDefined(): void - { - $container = new Container; - - $container->when(ContainerTestContextInjectVariadic::class)->needs(IContainerContextContractStub::class)->giveTagged('stub'); - - $resolvedInstance = $container->make(ContainerTestContextInjectVariadic::class); - - $this->assertCount(0, $resolvedInstance->stubs); - } - - public function testContextualBindingGivesTagsForArray(): void - { - $container = new Container; - - $container->tag([ - ContainerContextImplementationStub::class, - ContainerContextImplementationStubTwo::class, - ], ['stub']); - - $container->when(ContainerTestContextInjectArray::class)->needs('$stubs')->giveTagged('stub'); - - $resolvedInstance = $container->make(ContainerTestContextInjectArray::class); - - $this->assertCount(2, $resolvedInstance->stubs); - $this->assertInstanceOf(ContainerContextImplementationStub::class, $resolvedInstance->stubs[0]); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $resolvedInstance->stubs[1]); - } - - public function testContextualBindingGivesTagsForVariadic(): void - { - $container = new Container; - - $container->tag([ - ContainerContextImplementationStub::class, - ContainerContextImplementationStubTwo::class, - ], ['stub']); - - $container->when(ContainerTestContextInjectVariadic::class)->needs(IContainerContextContractStub::class)->giveTagged('stub'); - - $resolvedInstance = $container->make(ContainerTestContextInjectVariadic::class); - - $this->assertCount(2, $resolvedInstance->stubs); - $this->assertInstanceOf(ContainerContextImplementationStub::class, $resolvedInstance->stubs[0]); - $this->assertInstanceOf(ContainerContextImplementationStubTwo::class, $resolvedInstance->stubs[1]); - } - - public function testContextualBindingGivesValuesFromConfigOptionalValueNull(): void - { - $config = $this->getConfigWithData('test', [ - 'username' => 'laravel', - 'password' => 'hunter42' - ]); - - $container = new Container; - $container->singleton('config', fn() => $config); - - $container - ->when(ContainerTestContextInjectFromConfigIndividualValues::class) - ->needs('$username') - ->giveConfig('test.username'); - - $container - ->when(ContainerTestContextInjectFromConfigIndividualValues::class) - ->needs('$password') - ->giveConfig('test.password'); - - $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); - - $this->assertSame('laravel', $resolvedInstance->username); - $this->assertSame('hunter42', $resolvedInstance->password); - $this->assertNull($resolvedInstance->alias); - } - - public function testContextualBindingGivesValuesFromConfigOptionalValueSet(): void - { - $config = $this->getConfigWithData('test', [ - 'username' => 'laravel', - 'password' => 'hunter42', - 'alias' => 'lumen' - ]); - - $container = new Container; - $container->singleton('config', fn() => $config); - - $container - ->when(ContainerTestContextInjectFromConfigIndividualValues::class) - ->needs('$username') - ->giveConfig('test.username'); - - $container - ->when(ContainerTestContextInjectFromConfigIndividualValues::class) - ->needs('$password') - ->giveConfig('test.password'); - - $container - ->when(ContainerTestContextInjectFromConfigIndividualValues::class) - ->needs('$alias') - ->giveConfig('test.alias'); - - $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); - - $this->assertSame('laravel', $resolvedInstance->username); - $this->assertSame('hunter42', $resolvedInstance->password); - $this->assertSame('lumen', $resolvedInstance->alias); - } - - public function testContextualBindingGivesValuesFromConfigWithDefault(): void - { - $config = $this->getConfigWithData('test', [ - 'password' => 'hunter42' - ]); - - $container = new Container; - $container->singleton('config', fn() => $config); - - $container - ->when(ContainerTestContextInjectFromConfigIndividualValues::class) - ->needs('$username') - ->giveConfig('test.username', 'DEFAULT_USERNAME'); - - $container - ->when(ContainerTestContextInjectFromConfigIndividualValues::class) - ->needs('$password') - ->giveConfig('test.password'); - - $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigIndividualValues::class); - - $this->assertSame('DEFAULT_USERNAME', $resolvedInstance->username); - $this->assertSame('hunter42', $resolvedInstance->password); - $this->assertNull($resolvedInstance->alias); - } - - public function testContextualBindingGivesValuesFromConfigArray(): void - { - $config = $this->getConfigWithData('test', [ - 'username' => 'laravel', - 'password' => 'hunter42', - 'alias' => 'lumen' - ]); - - $container = new Container; - $container->singleton('config', fn() => $config); - - $container - ->when(ContainerTestContextInjectFromConfigArray::class) - ->needs('$settings') - ->giveConfig('test'); - - $resolvedInstance = $container->make(ContainerTestContextInjectFromConfigArray::class); - - $this->assertSame('laravel', $resolvedInstance->settings['username']); - $this->assertSame('hunter42', $resolvedInstance->settings['password']); - $this->assertSame('lumen', $resolvedInstance->settings['alias']); - } - - private function getConfigWithData(string $groupName, array $data = []): Repository { - $loader = $this->prophesize(\Illuminate\Config\LoaderInterface::class); - $loader->load(\Prophecy\Argument::any(), $groupName, \Prophecy\Argument::any())->willReturn($data); - return new Repository($loader->reveal(), 'production'); - } -} - -class ContainerContextualConcreteStub {} - -interface IContainerContextualContractStub {} - -class ContainerContextualImplementationStub implements IContainerContextualContractStub {} - -class ContainerInjectVariableStub -{ - public $something; - - public function __construct(ContainerContextualConcreteStub $concrete, $something) - { - $this->something = $something; - } -} - -interface IContainerContextContractStub -{ - // -} - -class ContainerContextNonContractStub -{ - // -} - -class ContainerContextImplementationStub implements IContainerContextContractStub -{ - // -} - -class ContainerContextImplementationStubTwo implements IContainerContextContractStub -{ - // -} - -class ContainerTestContextInjectInstantiations implements IContainerContextContractStub -{ - public static $instantiations; - - public function __construct() - { - static::$instantiations++; - } -} - -class ContainerTestContextInjectOne -{ - public $impl; - - public function __construct(IContainerContextContractStub $impl) - { - $this->impl = $impl; - } -} - -class ContainerTestContextInjectTwo -{ - public $impl; - - public function __construct(IContainerContextContractStub $impl) - { - $this->impl = $impl; - } -} - -class ContainerTestContextInjectThree -{ - public $impl; - - public function __construct(IContainerContextContractStub $impl) - { - $this->impl = $impl; - } -} - -class ContainerTestContextInjectTwoInstances -{ - public $implOne; - public $implTwo; - - public function __construct(ContainerTestContextWithOptionalInnerDependency $implOne, ContainerTestContextInjectTwo $implTwo) - { - $this->implOne = $implOne; - $this->implTwo = $implTwo; - } -} - -class ContainerTestContextWithOptionalInnerDependency -{ - public $inner; - - public function __construct(?ContainerTestContextInjectOne $inner = null) - { - $this->inner = $inner; - } -} - -class ContainerTestContextInjectArray -{ - public $stubs; - - public function __construct(array $stubs) - { - $this->stubs = $stubs; - } -} - -class ContainerTestContextInjectVariadic -{ - public array $stubs; - - public function __construct(IContainerContextContractStub ...$stubs) - { - $this->stubs = $stubs; - } -} - -class ContainerTestContextInjectVariadicAfterNonVariadic -{ - public $other; - public $stubs; - - public function __construct(ContainerContextNonContractStub $other, IContainerContextContractStub ...$stubs) - { - $this->other = $other; - $this->stubs = $stubs; - } -} - -class ContainerTestContextInjectFromConfigIndividualValues -{ - public $username; - public $password; - public $alias = null; - - public function __construct($username, $password, $alias = null) - { - $this->username = $username; - $this->password = $password; - $this->alias = $alias; - } -} - -class ContainerTestContextInjectFromConfigArray -{ - public $settings; - - public function __construct($settings) - { - $this->settings = $settings; - } -} \ No newline at end of file diff --git a/tests/Container/ContainerExtendTest.php b/tests/Container/ContainerExtendTest.php deleted file mode 100644 index f19659028..000000000 --- a/tests/Container/ContainerExtendTest.php +++ /dev/null @@ -1,200 +0,0 @@ -extend('foo', function ($old, $container) { - return $old.'bar'; - }); - - $this->assertSame('foobar', $container->make('foo')); - - $container = new Container; - - $container->singleton('foo', function () { - return (object) ['name' => 'taylor']; - }); - $container->extend('foo', function ($old, $container) { - $old->age = 26; - - return $old; - }); - - $result = $container->make('foo'); - - $this->assertSame('taylor', $result->name); - $this->assertEquals(26, $result->age); - $this->assertSame($result, $container->make('foo')); - } - - public function testExtendInstancesArePreserved(): void - { - $container = new Container; - $container->bind('foo', function () { - $obj = new stdClass; - $obj->foo = 'bar'; - - return $obj; - }); - - $obj = new stdClass; - $obj->foo = 'foo'; - $container->instance('foo', $obj); - $container->extend('foo', function ($obj, $container) { - $obj->bar = 'baz'; - - return $obj; - }); - $container->extend('foo', function ($obj, $container) { - $obj->baz = 'foo'; - - return $obj; - }); - - $this->assertSame('foo', $container->make('foo')->foo); - $this->assertSame('baz', $container->make('foo')->bar); - $this->assertSame('foo', $container->make('foo')->baz); - } - - public function testExtendIsLazyInitialized(): void - { - ContainerExtLazyExtendStub::$initialized = false; - - $container = new Container; - $container->bind(ContainerExtLazyExtendStub::class); - $container->extend(ContainerExtLazyExtendStub::class, function ($obj, $container) { - $obj->init(); - - return $obj; - }); - $this->assertFalse(ContainerExtLazyExtendStub::$initialized); - $container->make(ContainerExtLazyExtendStub::class); - $this->assertTrue(ContainerExtLazyExtendStub::$initialized); - } - - public function testExtendCanBeCalledBeforeBind(): void - { - $container = new Container; - $container->extend('foo', function ($old, $container) { - return $old.'bar'; - }); - $container['foo'] = 'foo'; - - $this->assertSame('foobar', $container->make('foo')); - } - - public function testExtendInstanceRebindingCallback(): void - { - $_SERVER['_test_rebind'] = false; - - $container = new Container; - $container->rebinding('foo', function () { - $_SERVER['_test_rebind'] = true; - }); - - $obj = new stdClass; - $container->instance('foo', $obj); - - $container->extend('foo', function ($obj, $container) { - return $obj; - }); - - $this->assertTrue($_SERVER['_test_rebind']); - } - - public function testExtendBindRebindingCallback(): void - { - $_SERVER['_test_rebind'] = false; - - $container = new Container; - $container->rebinding('foo', function () { - $_SERVER['_test_rebind'] = true; - }); - $container->bind('foo', function () { - return new stdClass; - }); - - $this->assertFalse($_SERVER['_test_rebind']); - - $container->make('foo'); - - $container->extend('foo', function ($obj, $container) { - return $obj; - }); - - $this->assertTrue($_SERVER['_test_rebind']); - } - - public function testExtensionWorksOnAliasedBindings(): void - { - $container = new Container; - $container->singleton('something', function () { - return 'some value'; - }); - $container->alias('something', 'something-alias'); - $container->extend('something-alias', function ($value) { - return $value.' extended'; - }); - - $this->assertSame('some value extended', $container->make('something')); - } - - public function testMultipleExtends(): void - { - $container = new Container; - $container['foo'] = 'foo'; - $container->extend('foo', function ($old, $container) { - return $old.'bar'; - }); - $container->extend('foo', function ($old, $container) { - return $old.'baz'; - }); - - $this->assertSame('foobarbaz', $container->make('foo')); - } - - public function testUnsetExtend(): void - { - $container = new Container; - $container->bind('foo', function () { - $obj = new stdClass; - $obj->foo = 'bar'; - - return $obj; - }); - - $container->extend('foo', function ($obj, $container) { - $obj->bar = 'baz'; - - return $obj; - }); - - unset($container['foo']); - $container->forgetExtenders('foo'); - - $container->bind('foo', function () { - return 'foo'; - }); - - $this->assertSame('foo', $container->make('foo')); - } -} - -class ContainerExtLazyExtendStub -{ - public static $initialized = false; - - public function init(): void - { - static::$initialized = true; - } -} \ No newline at end of file diff --git a/tests/Container/ContainerL4Test.php b/tests/Container/ContainerL4Test.php deleted file mode 100755 index 95ce3a3dc..000000000 --- a/tests/Container/ContainerL4Test.php +++ /dev/null @@ -1,366 +0,0 @@ -bind('name', function() { return 'Taylor'; }); - $this->assertEquals('Taylor', $container->make('name')); - } - - - public function testBindIfDoesntRegisterIfServiceAlreadyRegistered(): void - { - $container = new Container; - $container->bind('name', function() { return 'Taylor'; }); - $container->bindIf('name', function() { return 'Dayle'; }); - - $this->assertEquals('Taylor', $container->make('name')); - } - - - public function testSharedClosureResolution(): void - { - $container = new Container; - $class = new stdClass; - $container->singleton('class', function() use ($class) { return $class; }); - $this->assertSame($class, $container->make('class')); - } - - - public function testAutoConcreteResolution(): void - { - $container = new Container; - $this->assertInstanceOf( - ContainerConcreteStub::class, - $container->make(ContainerConcreteStub::class) - ); - } - - - public function testSlashesAreHandled(): void - { - $container = new Container; - $container->bind('\Foo', function() { return 'hello'; }); - $this->assertEquals('hello', $container->make('Foo')); - } - - - public function testParametersCanOverrideDependencies(): void - { - $container = new Container; - $stub = new ContainerDependentStub($mock = m::mock(IContainerContractStub::class)); - $resolved = $container->make(ContainerNestedDependentStub::class, [$stub]); - $this->assertInstanceOf(ContainerNestedDependentStub::class, $resolved); - $this->assertEquals($mock, $resolved->inner->impl); - } - - - public function testSharedConcreteResolution(): void - { - $container = new Container; - $container->singleton(ContainerConcreteStub::class); - $bindings = $container->getBindings(); - - $var1 = $container->make(ContainerConcreteStub::class); - $var2 = $container->make(ContainerConcreteStub::class); - $this->assertSame($var1, $var2); - } - - public function testSingletonIfDoesntRegisterIfBindingAlreadyRegistered(): void - { - $container = new Container; - $container->singleton('class', function () { - return new stdClass; - }); - $firstInstantiation = $container->make('class'); - $container->singletonIf('class', function () { - return new ContainerConcreteStub; - }); - $secondInstantiation = $container->make('class'); - $this->assertSame($firstInstantiation, $secondInstantiation); - } - - public function testSingletonIfDoesRegisterIfBindingNotRegisteredYet(): void - { - $container = new Container; - $container->singleton('class', function () { - return new stdClass; - }); - $container->singletonIf('otherClass', function () { - return new ContainerConcreteStub; - }); - $firstInstantiation = $container->make('otherClass'); - $secondInstantiation = $container->make('otherClass'); - $this->assertSame($firstInstantiation, $secondInstantiation); - } - - public function testAbstractToConcreteResolution(): void - { - $container = new Container; - $container->bind(IContainerContractStub::class, ContainerImplementationStub::class); - $class = $container->make(ContainerDependentStub::class); - $this->assertInstanceOf(ContainerImplementationStub::class, $class->impl); - } - - - public function testNestedDependencyResolution(): void - { - $container = new Container; - $container->bind(IContainerContractStub::class, ContainerImplementationStub::class); - $class = $container->make(ContainerNestedDependentStub::class); - $this->assertInstanceOf(ContainerDependentStub::class, $class->inner); - $this->assertInstanceOf(ContainerImplementationStub::class, $class->inner->impl); - } - - - public function testContainerIsPassedToResolvers(): void - { - $container = new Container; - $container->bind('something', function($c) { return $c; }); - $c = $container->make('something'); - $this->assertSame($c, $container); - } - - - public function testArrayAccess(): void - { - $container = new Container; - $container['something'] = function() { return 'foo'; }; - $this->assertTrue(isset($container['something'])); - $this->assertEquals('foo', $container['something']); - unset($container['something']); - $this->assertFalse(isset($container['something'])); - } - - - public function testAliases(): void - { - $container = new Container; - $container['foo'] = 'bar'; - $container->alias('foo', 'baz'); - $this->assertEquals('bar', $container->make('foo')); - $this->assertEquals('bar', $container->make('baz')); - $container->bind(['bam' => 'boom'], function() { return 'pow'; }); - $this->assertEquals('pow', $container->make('bam')); - $this->assertEquals('pow', $container->make('boom')); - $container->instance(['zoom' => 'zing'], 'wow'); - $this->assertEquals('wow', $container->make('zoom')); - $this->assertEquals('wow', $container->make('zing')); - } - - - public function testShareMethod(): void - { - $container = new Container; - $closure = $container->share(function() { return new stdClass; }); - $class1 = $closure($container); - $class2 = $closure($container); - $this->assertSame($class1, $class2); - } - - public function testBindingsCanBeOverridden(): void - { - $container = new Container; - $container['foo'] = 'bar'; - $foo = $container['foo']; - $container['foo'] = 'baz'; - $this->assertEquals('baz', $container['foo']); - } - - public function testParametersCanBePassedThroughToClosure(): void - { - $container = new Container; - $container->bind('foo', function($c, $parameters) - { - return $parameters; - }); - - $this->assertEquals([1, 2, 3], $container->make('foo', [1, 2, 3])); - } - - public function testResolutionOfDefaultParameters(): void - { - $container = new Container; - $instance = $container->make(ContainerDefaultValueStub::class); - $this->assertInstanceOf(ContainerConcreteStub::class, $instance->stub); - $this->assertEquals('taylor', $instance->default); - } - - - public function testResolvingCallbacksAreCalledForSpecificAbstracts(): void - { - $container = new Container; - $container->resolving('foo', function($object) { return $object->name = 'taylor'; }); - $container->bind('foo', function() { return new StdClass; }); - $instance = $container->make('foo'); - - $this->assertEquals('taylor', $instance->name); - } - - - public function testResolvingCallbacksAreCalled(): void - { - $container = new Container; - $container->resolvingAny(function($object) { return $object->name = 'taylor'; }); - $container->bind('foo', function() { return new StdClass; }); - $instance = $container->make('foo'); - - $this->assertEquals('taylor', $instance->name); - } - - - public function testUnsetRemoveBoundInstances(): void - { - $container = new Container; - $container->instance('object', new StdClass); - unset($container['object']); - - $this->assertFalse($container->bound('object')); - } - - - public function testReboundListeners(): void - { - unset($_SERVER['__test.rebind']); - - $container = new Container; - $container->bind('foo', function() {}); - $container->rebinding('foo', function() { $_SERVER['__test.rebind'] = true; }); - $container->bind('foo', function() {}); - - $this->assertTrue($_SERVER['__test.rebind']); - } - - - public function testReboundListenersOnInstances(): void - { - unset($_SERVER['__test.rebind']); - - $container = new Container; - $container->instance('foo', function() {}); - $container->rebinding('foo', function() { $_SERVER['__test.rebind'] = true; }); - $container->instance('foo', function() {}); - - $this->assertTrue($_SERVER['__test.rebind']); - } - - - public function testPassingSomePrimitiveParameters(): void - { - $container = new Container; - $value = $container->make(ContainerMixedPrimitiveStub::class, ['first' => 'taylor', 'last' => 'otwell']); - $this->assertInstanceOf(ContainerMixedPrimitiveStub::class, $value); - $this->assertEquals('taylor', $value->first); - $this->assertEquals('otwell', $value->last); - $this->assertInstanceOf(ContainerConcreteStub::class, $value->stub); - - $container = new Container; - $value = $container->make(ContainerMixedPrimitiveStub::class, [0 => 'taylor', 2 => 'otwell']); - $this->assertInstanceOf(ContainerMixedPrimitiveStub::class, $value); - $this->assertEquals('taylor', $value->first); - $this->assertEquals('otwell', $value->last); - $this->assertInstanceOf(ContainerConcreteStub::class, $value->stub); - } - - - public function testCreatingBoundConcreteClassPassesParameters(): void - { - $container = new Container; - $container->bind('TestAbstractClass', ContainerConstructorParameterLoggingStub::class); - $parameters = ['First', 'Second']; - $instance = $container->make('TestAbstractClass', $parameters); - $this->assertEquals($parameters, $instance->receivedParameters); - } - - - public function testInternalClassWithDefaultParameters(): void - { - $this->expectException(BindingResolutionException::class, 'Unresolvable dependency resolving [Parameter #0 [ $first ]] in class ContainerMixedPrimitiveStub'); - $container = new Container; - $parameters = []; - $container->make('ContainerMixedPrimitiveStub', $parameters); - } - - - public function testUnsetAffectsResolved(): void - { - $container = new Container; - $container->make(ContainerConcreteStub::class); - - unset($container[ContainerConcreteStub::class]); - $this->assertFalse($container->resolved(ContainerConcreteStub::class)); - } - -} - -class ContainerConcreteStub {} - -interface IContainerContractStub {} - -class ContainerImplementationStub implements IContainerContractStub {} - -class ContainerDependentStub { - public $impl; - public function __construct(IContainerContractStub $impl) - { - $this->impl = $impl; - } -} - -class ContainerNestedDependentStub { - public $inner; - public function __construct(ContainerDependentStub $inner) - { - $this->inner = $inner; - } -} - -class ContainerDefaultValueStub { - public $stub; public $default; - public function __construct(ContainerConcreteStub $stub, $default = 'taylor') - { - $this->stub = $stub; - $this->default = $default; - } -} - -class ContainerMixedPrimitiveStub { - public function __construct(public $first, public ContainerConcreteStub $stub, public $last) - {} -} - -class ContainerConstructorParameterLoggingStub { - public $receivedParameters; - - public function __construct($first, $second) - { - $this->receivedParameters = func_get_args(); - } -} - -class ContainerLazyExtendStub { - public static $initialized = false; - public function init(): void - { static::$initialized = true; } -} diff --git a/tests/Container/ContainerNewTest.php b/tests/Container/ContainerNewTest.php deleted file mode 100644 index d4fd2cfea..000000000 --- a/tests/Container/ContainerNewTest.php +++ /dev/null @@ -1,690 +0,0 @@ -assertSame($container, Container::getInstance()); - - Container::setInstance(null); - - $container2 = Container::getInstance(); - - $this->assertInstanceOf(Container::class, $container2); - $this->assertNotSame($container, $container2); - } - - public function testClosureResolution(): void - { - $container = new Container; - $container->bind('name', function () { - return 'Taylor'; - }); - $this->assertSame('Taylor', $container->make('name')); - } - - public function testBindIfDoesntRegisterIfServiceAlreadyRegistered(): void - { - $container = new Container; - $container->bind('name', function () { - return 'Taylor'; - }); - $container->bindIf('name', function () { - return 'Dayle'; - }); - - $this->assertSame('Taylor', $container->make('name')); - } - - public function testBindIfDoesRegisterIfServiceNotRegisteredYet(): void - { - $container = new Container; - $container->bind('surname', function () { - return 'Taylor'; - }); - $container->bindIf('name', function () { - return 'Dayle'; - }); - - $this->assertSame('Dayle', $container->make('name')); - } - - public function testSingletonIfDoesntRegisterIfBindingAlreadyRegistered(): void - { - $container = new Container; - $container->singleton('class', function () { - return new stdClass; - }); - $firstInstantiation = $container->make('class'); - $container->singletonIf('class', function () { - return new ContainerNewConcreteStub; - }); - $secondInstantiation = $container->make('class'); - $this->assertSame($firstInstantiation, $secondInstantiation); - } - - public function testSingletonIfDoesRegisterIfBindingNotRegisteredYet(): void - { - $container = new Container; - $container->singleton('class', function () { - return new stdClass; - }); - $container->singletonIf('otherClass', function () { - return new ContainerNewConcreteStub; - }); - $firstInstantiation = $container->make('otherClass'); - $secondInstantiation = $container->make('otherClass'); - $this->assertSame($firstInstantiation, $secondInstantiation); - } - - public function testSharedClosureResolution(): void - { - $container = new Container; - $container->singleton('class', function () { - return new stdClass; - }); - $firstInstantiation = $container->make('class'); - $secondInstantiation = $container->make('class'); - $this->assertSame($firstInstantiation, $secondInstantiation); - } - - public function testAutoConcreteResolution(): void - { - $container = new Container; - $this->assertInstanceOf(ContainerNewConcreteStub::class, $container->make(ContainerNewConcreteStub::class)); - } - - public function testSharedConcreteResolution(): void - { - $container = new Container; - $container->singleton(ContainerNewConcreteStub::class); - - $var1 = $container->make(ContainerNewConcreteStub::class); - $var2 = $container->make(ContainerNewConcreteStub::class); - $this->assertSame($var1, $var2); - } - - public function testBindFailsLoudlyWithInvalidArgument(): void - { - $this->expectException(TypeError::class); - $container = new Container; - - $concrete = new ContainerNewConcreteStub; - $container->bind(ContainerNewConcreteStub::class, $concrete); - } - - public function testAbstractToConcreteResolution(): void - { - $container = new Container; - $container->bind(IContainerNewContractStub::class, ContainerNewImplementationStub::class); - $class = $container->make(ContainerNewDependentStub::class); - $this->assertInstanceOf(ContainerNewImplementationStub::class, $class->impl); - } - - public function testNestedDependencyResolution(): void - { - $container = new Container; - $container->bind(IContainerNewContractStub::class, ContainerNewImplementationStub::class); - $class = $container->make(ContainerNewNestedDependentStub::class); - $this->assertInstanceOf(ContainerNewDependentStub::class, $class->inner); - $this->assertInstanceOf(ContainerNewImplementationStub::class, $class->inner->impl); - } - - public function testContainerIsPassedToResolvers(): void - { - $container = new Container; - $container->bind('something', function ($c) { - return $c; - }); - $c = $container->make('something'); - $this->assertSame($c, $container); - } - - public function testArrayAccess(): void - { - $container = new Container; - $container['something'] = function () { - return 'foo'; - }; - $this->assertTrue(isset($container['something'])); - $this->assertSame('foo', $container['something']); - unset($container['something']); - $this->assertFalse(isset($container['something'])); - } - - public function testAliases(): void - { - $container = new Container; - $container['foo'] = 'bar'; - $container->alias('foo', 'baz'); - $container->alias('baz', 'bat'); - $this->assertSame('bar', $container->make('foo')); - $this->assertSame('bar', $container->make('baz')); - $this->assertSame('bar', $container->make('bat')); - } - - public function testAliasesWithArrayOfParameters(): void - { - $container = new Container; - $container->bind('foo', function ($app, $config) { - return $config; - }); - $container->alias('foo', 'baz'); - $this->assertEquals([1, 2, 3], $container->make('baz', [1, 2, 3])); - } - - public function testBindingsCanBeOverridden(): void - { - $container = new Container; - $container['foo'] = 'bar'; - $container['foo'] = 'baz'; - $this->assertSame('baz', $container['foo']); - } - - public function testBindingAnInstanceReturnsTheInstance(): void - { - $container = new Container; - - $bound = new stdClass; - $resolved = $container->instance('foo', $bound); - - $this->assertSame($bound, $resolved); - } - - public function testBindingAnInstanceAsShared(): void - { - $container = new Container; - $bound = new stdClass; - $container->instance('foo', $bound); - $object = $container->make('foo'); - $this->assertSame($bound, $object); - } - - public function testResolutionOfDefaultParameters(): void - { - $container = new Container; - $instance = $container->make(ContainerNewDefaultValueStub::class); - $this->assertInstanceOf(ContainerNewConcreteStub::class, $instance->stub); - $this->assertSame('taylor', $instance->default); - } - - public function testUnsetRemoveBoundInstances(): void - { - $container = new Container; - $container->instance('object', new stdClass); - unset($container['object']); - - $this->assertFalse($container->bound('object')); - } - - public function testBoundInstanceAndAliasCheckViaArrayAccess(): void - { - $container = new Container; - $container->instance('object', new stdClass); - $container->alias('object', 'alias'); - - $this->assertTrue(isset($container['object'])); - $this->assertTrue(isset($container['alias'])); - } - - public function testReboundListeners(): void - { - unset($_SERVER['__test.rebind']); - - $container = new Container; - $container->bind('foo', function () { - // - }); - $container->rebinding('foo', function () { - $_SERVER['__test.rebind'] = true; - }); - $container->bind('foo', function () { - // - }); - - $this->assertTrue($_SERVER['__test.rebind']); - } - - public function testReboundListenersOnInstances(): void - { - unset($_SERVER['__test.rebind']); - - $container = new Container; - $container->instance('foo', function () { - // - }); - $container->rebinding('foo', function () { - $_SERVER['__test.rebind'] = true; - }); - $container->instance('foo', function () { - // - }); - - $this->assertTrue($_SERVER['__test.rebind']); - } - - public function testReboundListenersOnInstancesOnlyFiresIfWasAlreadyBound(): void - { - $_SERVER['__test.rebind'] = false; - - $container = new Container; - $container->rebinding('foo', function () { - $_SERVER['__test.rebind'] = true; - }); - $container->instance('foo', function () { - // - }); - - $this->assertFalse($_SERVER['__test.rebind']); - } - - public function testInternalClassWithDefaultParameters(): void - { - $this->expectException(BindingResolutionException::class); - $this->expectExceptionMessage('Unresolvable dependency resolving [Parameter #0 [ $first ]] in class Illuminate\Tests\Container\ContainerNewMixedPrimitiveStub'); - - $container = new Container; - $container->make(ContainerNewMixedPrimitiveStub::class, []); - } - - public function testBindingResolutionExceptionMessage(): void - { - $this->expectException(BindingResolutionException::class); - $this->expectExceptionMessage('Target [Illuminate\Tests\Container\IContainerNewContractStub] is not instantiable.'); - - $container = new Container; - $container->make(IContainerNewContractStub::class, []); - } - - public function testBindingResolutionExceptionMessageIncludesBuildStack(): void - { - $this->expectException(BindingResolutionException::class); - $this->expectExceptionMessage('Target [Illuminate\Tests\Container\IContainerNewContractStub] is not instantiable while building [Illuminate\Tests\Container\ContainerNewDependentStub].'); - - $container = new Container; - $container->make(ContainerNewDependentStub::class, []); - } - - public function testBindingResolutionExceptionMessageWhenClassDoesNotExist(): void - { - $this->expectException(BindingResolutionException::class); - $this->expectExceptionMessage('Target class [Foo\Bar\Baz\DummyClass] does not exist.'); - - $container = new Container; - $container->build('Foo\Bar\Baz\DummyClass'); - } - - public function testForgetInstanceForgetsInstance(): void - { - $container = new Container; - $containerConcreteStub = new ContainerNewConcreteStub; - $container->instance(ContainerNewConcreteStub::class, $containerConcreteStub); - $this->assertTrue($container->isShared(ContainerNewConcreteStub::class)); - $container->forgetInstance(ContainerNewConcreteStub::class); - $this->assertFalse($container->isShared(ContainerNewConcreteStub::class)); - } - - public function testForgetInstancesForgetsAllInstances(): void - { - $container = new Container; - $containerConcreteStub1 = new ContainerNewConcreteStub; - $containerConcreteStub2 = new ContainerNewConcreteStub; - $containerConcreteStub3 = new ContainerNewConcreteStub; - $container->instance('Instance1', $containerConcreteStub1); - $container->instance('Instance2', $containerConcreteStub2); - $container->instance('Instance3', $containerConcreteStub3); - $this->assertTrue($container->isShared('Instance1')); - $this->assertTrue($container->isShared('Instance2')); - $this->assertTrue($container->isShared('Instance3')); - $container->forgetInstances(); - $this->assertFalse($container->isShared('Instance1')); - $this->assertFalse($container->isShared('Instance2')); - $this->assertFalse($container->isShared('Instance3')); - } - - public function testContainerFlushFlushesAllBindingsAliasesAndResolvedInstances(): void - { - $container = new Container; - $container->bind('ConcreteStub', function () { - return new ContainerNewConcreteStub; - }, true); - $container->alias('ConcreteStub', 'ContainerConcreteStub'); - $container->make('ConcreteStub'); - $this->assertTrue($container->resolved('ConcreteStub')); - $this->assertTrue($container->isAlias('ContainerConcreteStub')); - $this->assertArrayHasKey('ConcreteStub', $container->getBindings()); - $this->assertTrue($container->isShared('ConcreteStub')); - $container->flush(); - $this->assertFalse($container->resolved('ConcreteStub')); - $this->assertFalse($container->isAlias('ContainerConcreteStub')); - $this->assertEmpty($container->getBindings()); - $this->assertFalse($container->isShared('ConcreteStub')); - } - - public function testResolvedResolvesAliasToBindingNameBeforeChecking(): void - { - $container = new Container; - $container->bind('ConcreteStub', function () { - return new ContainerNewConcreteStub; - }, true); - $container->alias('ConcreteStub', 'foo'); - - $this->assertFalse($container->resolved('ConcreteStub')); - $this->assertFalse($container->resolved('foo')); - - $container->make('ConcreteStub'); - - $this->assertTrue($container->resolved('ConcreteStub')); - $this->assertTrue($container->resolved('foo')); - } - - public function testGetAlias(): void - { - $container = new Container; - $container->alias('ConcreteStub', 'foo'); - $this->assertSame('ConcreteStub', $container->getAlias('foo')); - } - - public function testItThrowsExceptionWhenAbstractIsSameAsAlias(): void - { - $this->expectException('LogicException'); - $this->expectExceptionMessage('[name] is aliased to itself.'); - - $container = new Container; - $container->alias('name', 'name'); - } - - public function testContainerGetFactory(): void - { - $container = new Container; - $container->bind('name', function () { - return 'Taylor'; - }); - - $factory = $container->factory('name'); - $this->assertEquals($container->make('name'), $factory()); - } - - public function testMakeWithMethodIsAnAliasForMakeMethod(): void - { - $mock = $this->getMockBuilder(Container::class) - ->onlyMethods(['make']) - ->getMock(); - - $mock->expects($this->once()) - ->method('make') - ->with(ContainerNewDefaultValueStub::class, ['default' => 'laurence']) - ->willReturn(new stdClass); - - $result = $mock->makeWith(ContainerNewDefaultValueStub::class, ['default' => 'laurence']); - - $this->assertInstanceOf(stdClass::class, $result); - } - - public function testResolvingWithArrayOfParameters(): void - { - $container = new Container; - $instance = $container->make(ContainerNewDefaultValueStub::class, ['default' => 'adam']); - $this->assertSame('adam', $instance->default); - - $instance = $container->make(ContainerNewDefaultValueStub::class); - $this->assertSame('taylor', $instance->default); - - $container->bind('foo', function ($app, $config) { - return $config; - }); - - $this->assertEquals([1, 2, 3], $container->make('foo', [1, 2, 3])); - } - - public function testResolvingWithUsingAnInterface(): void - { - $container = new Container; - $container->bind(IContainerNewContractStub::class, ContainerNewInjectVariableStubWithInterfaceImplementation::class); - $instance = $container->make(IContainerNewContractStub::class, ['something' => 'laurence']); - $this->assertSame('laurence', $instance->something); - } - - public function testNestedParameterOverride(): void - { - $container = new Container; - $container->bind('foo', function ($app, $config) { - return $app->make('bar', ['name' => 'Taylor']); - }); - $container->bind('bar', function ($app, $config) { - return $config; - }); - - $this->assertEquals(['name' => 'Taylor'], $container->make('foo', ['something'])); - } - - public function testNestedParametersAreResetForFreshMake(): void - { - $container = new Container; - - $container->bind('foo', function ($app, $config) { - return $app->make('bar'); - }); - - $container->bind('bar', function ($app, $config) { - return $config; - }); - - $this->assertEquals([], $container->make('foo', ['something'])); - } - - public function testSingletonBindingsNotRespectedWithMakeParameters(): void - { - $container = new Container; - - $container->singleton('foo', function ($app, $config) { - return $config; - }); - - $this->assertEquals(['name' => 'taylor'], $container->make('foo', ['name' => 'taylor'])); - $this->assertEquals(['name' => 'abigail'], $container->make('foo', ['name' => 'abigail'])); - } - - public function testCanBuildWithoutParameterStackWithNoConstructors(): void - { - $container = new Container; - $this->assertInstanceOf(ContainerNewConcreteStub::class, $container->build(ContainerNewConcreteStub::class)); - } - - public function testCanBuildWithoutParameterStackWithConstructors(): void - { - $container = new Container; - $container->bind(IContainerNewContractStub::class, ContainerNewImplementationStub::class); - $this->assertInstanceOf(ContainerNewDependentStub::class, $container->build(ContainerNewDependentStub::class)); - } - - public function testContainerKnowsEntry(): void - { - $container = new Container; - $container->bind(IContainerNewContractStub::class, ContainerNewImplementationStub::class); - $this->assertTrue($container->has(IContainerNewContractStub::class)); - } - - public function testContainerCanBindAnyWord(): void - { - $container = new Container; - $container->bind('Taylor', stdClass::class); - $this->assertInstanceOf(stdClass::class, $container->get('Taylor')); - } - - public function testContainerCanDynamicallySetService(): void - { - $container = new Container; - $this->assertFalse(isset($container['name'])); - $container['name'] = 'Taylor'; - $this->assertTrue(isset($container['name'])); - $this->assertSame('Taylor', $container['name']); - } - - public function testUnknownEntryThrowsException(): void - { - $this->expectException(EntryNotFoundException::class); - - $container = new Container; - $container->get('Taylor'); - } - - public function testBoundEntriesThrowsContainerExceptionWhenNotResolvable(): void - { - $this->expectException(BindingResolutionException::class); - - $container = new Container; - $container->bind('Taylor', IContainerNewContractStub::class); - - $container->get('Taylor'); - } - - public function testContainerCanResolveClasses(): void - { - $container = new Container; - $class = $container->get(ContainerNewConcreteStub::class); - - $this->assertInstanceOf(ContainerNewConcreteStub::class, $class); - } - - // public function testContainerCanCatchCircularDependency() - // { - // $this->expectException(\Illuminate\Contracts\Container\CircularDependencyException::class); - - // $container = new Container; - // $container->get(CircularAStub::class); - // } -} - -class CircularAStub -{ - public function __construct(CircularBStub $b) - { - // - } -} - -class CircularBStub -{ - public function __construct(CircularCStub $c) - { - // - } -} - -class CircularCStub -{ - public function __construct(CircularAStub $a) - { - // - } -} - -class ContainerNewConcreteStub -{ - // -} - -interface IContainerNewContractStub -{ - // -} - -class ContainerNewImplementationStub implements IContainerNewContractStub -{ - // -} - -class ContainerNewImplementationStubTwo implements IContainerNewContractStub -{ - // -} - -class ContainerNewDependentStub -{ - public $impl; - - public function __construct(IContainerNewContractStub $impl) - { - $this->impl = $impl; - } -} - -class ContainerNewNestedDependentStub -{ - public $inner; - - public function __construct(ContainerNewDependentStub $inner) - { - $this->inner = $inner; - } -} - -class ContainerNewDefaultValueStub -{ - public $stub; - public $default; - - public function __construct(ContainerNewConcreteStub $stub, $default = 'taylor') - { - $this->stub = $stub; - $this->default = $default; - } -} - -class ContainerNewMixedPrimitiveStub -{ - public $first; - public $last; - public $stub; - - public function __construct($first, ContainerNewConcreteStub $stub, $last) - { - $this->stub = $stub; - $this->last = $last; - $this->first = $first; - } -} - -class ContainerNewInjectVariableStub -{ - public $something; - - public function __construct(ContainerNewConcreteStub $concrete, $something) - { - $this->something = $something; - } -} - -class ContainerNewInjectVariableStubWithInterfaceImplementation implements IContainerNewContractStub -{ - public $something; - - public function __construct(ContainerNewConcreteStub $concrete, $something) - { - $this->something = $something; - } -} \ No newline at end of file diff --git a/tests/Container/ContainerResolveNonInstantiableTest.php b/tests/Container/ContainerResolveNonInstantiableTest.php deleted file mode 100644 index 2dae6b206..000000000 --- a/tests/Container/ContainerResolveNonInstantiableTest.php +++ /dev/null @@ -1,75 +0,0 @@ -make(ParentClass::class, ['i' => 42]); - - $this->assertSame(42, $object->i); - } - - public function testResolvingNonInstantiableWithVariadicRemovesWiths(): void - { - $container = new Container; - $parent = $container->make(VariadicParentClass::class, ['i' => 42]); - - $this->assertCount(0, $parent->child->objects); - $this->assertSame(42, $parent->i); - } -} - -interface TestInterface -{ -} - -class ParentClass -{ - /** - * @var int - */ - public $i; - - public function __construct(?TestInterface $testObject = null, int $i = 0) - { - $this->i = $i; - } -} - -class VariadicParentClass -{ - /** - * @var \Illuminate\Tests\Container\ChildClass - */ - public $child; - - /** - * @var int - */ - public $i; - - public function __construct(ChildClass $child, int $i = 0) - { - $this->child = $child; - $this->i = $i; - } -} - -class ChildClass -{ - /** - * @var array - */ - public $objects; - - public function __construct(TestInterface ...$objects) - { - $this->objects = $objects; - } -} diff --git a/tests/Container/ContainerTaggingTest.php b/tests/Container/ContainerTaggingTest.php deleted file mode 100644 index 4b5ca8482..000000000 --- a/tests/Container/ContainerTaggingTest.php +++ /dev/null @@ -1,105 +0,0 @@ -tag(ContainerImplementationTaggedStub::class, 'foo', 'bar'); - $container->tag(ContainerImplementationTaggedStubTwo::class, ['foo']); - - $this->assertCount(1, $container->tagged('bar')); - $this->assertCount(2, $container->tagged('foo')); - - $fooResults = []; - foreach ($container->tagged('foo') as $foo) { - $fooResults[] = $foo; - } - - $barResults = []; - foreach ($container->tagged('bar') as $bar) { - $barResults[] = $bar; - } - - $this->assertInstanceOf(ContainerImplementationTaggedStub::class, $fooResults[0]); - $this->assertInstanceOf(ContainerImplementationTaggedStub::class, $barResults[0]); - $this->assertInstanceOf(ContainerImplementationTaggedStubTwo::class, $fooResults[1]); - - $container = new Container; - $container->tag([ContainerImplementationTaggedStub::class, ContainerImplementationTaggedStubTwo::class], ['foo']); - $this->assertCount(2, $container->tagged('foo')); - - $fooResults = []; - foreach ($container->tagged('foo') as $foo) { - $fooResults[] = $foo; - } - - $this->assertInstanceOf(ContainerImplementationTaggedStub::class, $fooResults[0]); - $this->assertInstanceOf(ContainerImplementationTaggedStubTwo::class, $fooResults[1]); - - $this->assertCount(0, $container->tagged('this_tag_does_not_exist')); - } - - public function testTaggedServicesAreLazyLoaded(): void - { - $container = $this->createPartialMock(Container::class, ['make']); - $container->expects($this->once())->method('make')->willReturn(new ContainerImplementationTaggedStub); - - $container->tag(ContainerImplementationTaggedStub::class, ['foo']); - $container->tag(ContainerImplementationTaggedStubTwo::class, ['foo']); - - $fooResults = []; - foreach ($container->tagged('foo') as $foo) { - $fooResults[] = $foo; - break; - } - - $this->assertCount(2, $container->tagged('foo')); - $this->assertInstanceOf(ContainerImplementationTaggedStub::class, $fooResults[0]); - } - - public function testLazyLoadedTaggedServicesCanBeLoopedOverMultipleTimes(): void - { - $container = new Container; - $container->tag(ContainerImplementationTaggedStub::class, 'foo'); - $container->tag(ContainerImplementationTaggedStubTwo::class, ['foo']); - - $services = $container->tagged('foo'); - - $fooResults = []; - foreach ($services as $foo) { - $fooResults[] = $foo; - } - - $this->assertInstanceOf(ContainerImplementationTaggedStub::class, $fooResults[0]); - $this->assertInstanceOf(ContainerImplementationTaggedStubTwo::class, $fooResults[1]); - - $fooResults = []; - foreach ($services as $foo) { - $fooResults[] = $foo; - } - - $this->assertInstanceOf(ContainerImplementationTaggedStub::class, $fooResults[0]); - $this->assertInstanceOf(ContainerImplementationTaggedStubTwo::class, $fooResults[1]); - } -} - -interface IContainerTaggedContractStub -{ - // -} - -class ContainerImplementationTaggedStub implements IContainerTaggedContractStub -{ - // -} - -class ContainerImplementationTaggedStubTwo implements IContainerTaggedContractStub -{ - // -} diff --git a/tests/Container/ResolvingCallbackTest.php b/tests/Container/ResolvingCallbackTest.php deleted file mode 100644 index 58a93bf9e..000000000 --- a/tests/Container/ResolvingCallbackTest.php +++ /dev/null @@ -1,498 +0,0 @@ -resolving('foo', function ($object) { - return $object->name = 'taylor'; - }); - $container->bind('foo', function () { - return new stdClass; - }); - $instance = $container->make('foo'); - - $this->assertSame('taylor', $instance->name); - } - - public function testResolvingCallbacksAreCalled(): void - { - $container = new Container; - $container->resolving(function ($object) { - return $object->name = 'taylor'; - }); - $container->bind('foo', function () { - return new stdClass; - }); - $instance = $container->make('foo'); - - $this->assertSame('taylor', $instance->name); - } - - public function testResolvingCallbacksAreCalledForType(): void - { - $container = new Container; - $container->resolving(stdClass::class, function ($object) { - return $object->name = 'taylor'; - }); - $container->bind('foo', function () { - return new stdClass; - }); - $instance = $container->make('foo'); - - $this->assertSame('taylor', $instance->name); - } - - public function testResolvingCallbacksShouldBeFiredWhenCalledWithAliases(): void - { - $container = new Container; - $container->alias(stdClass::class, 'std'); - $container->resolving('std', function ($object) { - return $object->name = 'taylor'; - }); - $container->bind('foo', function () { - return new stdClass; - }); - $instance = $container->make('foo'); - - $this->assertSame('taylor', $instance->name); - } - - public function testResolvingCallbacksAreCalledOnceForImplementation(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testGlobalResolvingCallbacksAreCalledOnceForImplementation(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testResolvingCallbacksAreCalledOnceForSingletonConcretes(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function ($object) use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - $container->bind(ResolvingImplementationStub::class); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(3, $callCounter); - } - - public function testResolvingCallbacksCanStillBeAddedAfterTheFirstResolution(): void - { - $container = new Container; - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingImplementationStub::class); - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - } - - public function testResolvingCallbacksAreCanceledWhenInterfaceGetsBoundToSomeOtherConcrete(): void - { - $container = new Container; - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $callCounter = 0; - $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStubTwo::class); - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - } - - public function testResolvingCallbacksAreCalledOnceForStringAbstractions(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving('foo', function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind('foo', ResolvingImplementationStub::class); - - $container->make('foo'); - $this->assertEquals(1, $callCounter); - - $container->make('foo'); - $this->assertEquals(2, $callCounter); - } - - public function testResolvingCallbacksForConcretesAreCalledOnceForStringAbstractions(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind('foo', ResolvingImplementationStub::class); - $container->bind('bar', ResolvingImplementationStub::class); - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - - $container->make('foo'); - $this->assertEquals(2, $callCounter); - - $container->make('bar'); - $this->assertEquals(3, $callCounter); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(4, $callCounter); - } - - public function testResolvingCallbacksAreCalledOnceForImplementation2(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, function () { - return new ResolvingImplementationStub; - }); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(3, $callCounter); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(4, $callCounter); - } - - public function testRebindingDoesNotAffectResolvingCallbacks(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - $container->bind(ResolvingContractStub::class, function () { - return new ResolvingImplementationStub; - }); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(3, $callCounter); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(4, $callCounter); - } - - public function testParametersPassedIntoResolvingCallbacks(): void - { - $container = new Container; - - $container->resolving(ResolvingContractStub::class, function ($obj, $app) use ($container) { - $this->assertInstanceOf(ResolvingContractStub::class, $obj); - $this->assertInstanceOf(ResolvingImplementationStubTwo::class, $obj); - $this->assertSame($container, $app); - }); - - $container->afterResolving(ResolvingContractStub::class, function ($obj, $app) use ($container) { - $this->assertInstanceOf(ResolvingContractStub::class, $obj); - $this->assertInstanceOf(ResolvingImplementationStubTwo::class, $obj); - $this->assertSame($container, $app); - }); - - $container->afterResolving(function ($obj, $app) use ($container) { - $this->assertInstanceOf(ResolvingContractStub::class, $obj); - $this->assertInstanceOf(ResolvingImplementationStubTwo::class, $obj); - $this->assertSame($container, $app); - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStubTwo::class); - $container->make(ResolvingContractStub::class); - } - - public function testResolvingCallbacksAreCallWhenRebindHappenForResolvedAbstract(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStubTwo::class); - $this->assertEquals(2, $callCounter); - - $container->make(ResolvingImplementationStubTwo::class); - $this->assertEquals(3, $callCounter); - - $container->bind(ResolvingContractStub::class, function () { - return new ResolvingImplementationStubTwo; - }); - $this->assertEquals(4, $callCounter); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(5, $callCounter); - } - - public function testRebindingDoesNotAffectMultipleResolvingCallbacks(): void - { - $container = new Container; - - $callCounter = 0; - - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->resolving(ResolvingImplementationStubTwo::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - // it should call the callback for interface - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - - // it should call the callback for interface - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - - // should call the callback for the interface it implements - // plus the callback for ResolvingImplementationStubTwo. - $container->make(ResolvingImplementationStubTwo::class); - $this->assertEquals(4, $callCounter); - } - - public function testResolvingCallbacksAreCalledForInterfaces(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingContractStub::class); - - $this->assertEquals(1, $callCounter); - } - - public function testResolvingCallbacksAreCalledForConcretesWhenAttachedOnInterface(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testResolvingCallbacksAreCalledForConcretesWhenAttachedOnConcretes(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testResolvingCallbacksAreCalledForConcretesWithNoBinding(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testResolvingCallbacksAreCalledForInterFacesWithNoBinding(): void - { - $container = new Container; - - $callCounter = 0; - $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testAfterResolvingCallbacksAreCalledOnceForImplementation(): void - { - $container = new Container; - - $callCounter = 0; - $container->afterResolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - - $container->make(ResolvingContractStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testBeforeResolvingCallbacksAreCalled(): void - { - // Given a call counter initialized to zero. - $container = new Container; - $callCounter = 0; - - // And a contract/implementation stub binding. - $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class); - - // When we add a before resolving callback that increment the counter by one. - $container->beforeResolving(ResolvingContractStub::class, function () use (&$callCounter) { - $callCounter++; - }); - - // Then resolving the implementation stub increases the counter by one. - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - - // And resolving the contract stub increases the counter by one. - $container->make(ResolvingContractStub::class); - $this->assertEquals(2, $callCounter); - } - - public function testGlobalBeforeResolvingCallbacksAreCalled(): void - { - // Given a call counter initialized to zero. - $container = new Container; - $callCounter = 0; - - // When we add a global before resolving callback that increment that counter by one. - $container->beforeResolving(function () use (&$callCounter) { - $callCounter++; - }); - - // Then resolving anything increases the counter by one. - $container->make(ResolvingImplementationStub::class); - $this->assertEquals(1, $callCounter); - } -} - -interface ResolvingContractStub -{ - // -} - -class ResolvingImplementationStub implements ResolvingContractStub -{ - // -} - -class ResolvingImplementationStubTwo implements ResolvingContractStub -{ - // -} diff --git a/tests/Container/RewindableGeneratorTest.php b/tests/Container/RewindableGeneratorTest.php deleted file mode 100644 index b65c3498e..000000000 --- a/tests/Container/RewindableGeneratorTest.php +++ /dev/null @@ -1,41 +0,0 @@ -assertCount(999, $generator); - } - - public function testCountUsesProvidedValueAsCallback(): void - { - $called = 0; - - $generator = new RewindableGenerator(function () { - yield 'foo'; - }, function () use (&$called) { - $called++; - - return 500; - }); - - // the count callback is called lazily - $this->assertSame(0, $called); - - $this->assertCount(500, $generator); - - count($generator); - - // the count callback is called only once - $this->assertSame(1, $called); - } -} diff --git a/tests/Exception/HandlerTest.php b/tests/Exception/HandlerTest.php index 024c4ab0a..4283ad1d9 100644 --- a/tests/Exception/HandlerTest.php +++ b/tests/Exception/HandlerTest.php @@ -1,6 +1,6 @@ registerCoreContainerAliases(); - $app->bindShared('hash', function() { return new Illuminate\Hashing\BcryptHasher; }); + $app->singleton('hash', function() { return new Illuminate\Hashing\BcryptHasher; }); $this->assertInstanceOf(Illuminate\Contracts\Hashing\Hasher::class, $app->make(Illuminate\Contracts\Hashing\Hasher::class)); // BC: the pre-migration interface name must still resolve via make()/autowiring; @@ -206,7 +206,7 @@ class ApplicationDeferredSharedServiceProviderStub extends Illuminate\Support\Se protected $defer = true; public function register() { - $this->app->bindShared('foo', function() { + $this->app->singleton('foo', function() { return new StdClass; }); } @@ -247,7 +247,7 @@ class ApplicationMultiProviderStub extends Illuminate\Support\ServiceProvider { protected $defer = true; public function register() { - $this->app->bindShared('foo', function() { return 'foo'; }); - $this->app->bindShared('bar', function($app) { return $app['foo'].'bar'; }); + $this->app->singleton('foo', function() { return 'foo'; }); + $this->app->singleton('bar', function($app) { return $app['foo'].'bar'; }); } } diff --git a/tests/Mail/MailMailerTest.php b/tests/Mail/MailMailerTest.php index 7b6fea15a..b06d1e524 100755 --- a/tests/Mail/MailMailerTest.php +++ b/tests/Mail/MailMailerTest.php @@ -213,7 +213,7 @@ public function mail(Message $message): void $this->calledTimes++; } }; - $container['FooMailer'] = $container->share(fn() => $fooMailer); + $container->singleton('FooMailer', fn() => $fooMailer); $mailer->send('foo', ['data'], 'FooMailer'); From fb9072f6d4ffed90e6298416e22155b8d9b1ed92 Mon Sep 17 00:00:00 2001 From: agis Date: Fri, 18 Sep 2026 16:52:34 +0700 Subject: [PATCH 4/4] feat(foundation): add bindShared()/share() BC shims to Application (task 4.1, container swap) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit illuminate/container v13 dropped the L4 bindShared()/share() API. Fork src already moved to singleton() (commits 69421972/f1fff797), but third-party & vendor-fork service providers still call them on the app at boot and can't all be patched (tomgrohl/laravel4-php71-encrypter is third-party packagist). Re-expose both as thin BC shims on Foundation\Application (which extends the v13 container): bindShared($a,$c) => singleton($a,$c); share() returns the memoizing closure. Unblocks boot for spatie/laravel-blade-x, laracasts/commander, tomgrohl/laravel4-php71-encrypter, barryvdh/laravel-ide-helper. Transitional — remove at the Foundation swap (task 4.5). Fork suite green (1489). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/Illuminate/Foundation/Application.php | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 6e7796b31..784676e19 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -472,6 +472,45 @@ public function make($abstract, $parameters = array(), $raiseEvents = true) return parent::make($abstract, $parameters, $raiseEvents); } + /** + * Register a shared binding. + * + * ponytail: transitional BC shim for the L4 container API removed by + * illuminate/container v13. Kept so third-party/vendor providers that still + * call bindShared()/share() on the app (spatie/laravel-blade-x, + * laracasts/commander, tomgrohl/laravel4-php71-encrypter, barryvdh/laravel-ide-helper) + * keep booting. Remove at the Foundation swap (task 4.5); fork src already uses singleton(). + * + * @param string $abstract + * @param \Closure $closure + * @return void + */ + public function bindShared($abstract, Closure $closure): void + { + $this->singleton($abstract, $closure); + } + + /** + * Wrap a closure so the resolved instance is memoized. BC shim; see bindShared(). + * + * @param \Closure $closure + * @return \Closure + */ + public function share(Closure $closure): Closure + { + return function ($container) use ($closure) + { + static $object; + + if (is_null($object)) + { + $object = $closure($container); + } + + return $object; + }; + } + /** * Determine if the given abstract type has been bound. *