byteever / container
A powerful dependency injection container specifically designed for WordPress plugin development with advanced features like auto-wiring, service binding, and configuration management.
Requires
- php: >=7.4
Requires (Dev)
- byteever/byteever-sniffs: ^1.1.3
- codeception/codeception: ^5.0
- lucatume/wp-browser: ^4.0
- phpstan/phpstan: ^1.0
This package is auto-updated.
Last update: 2025-06-20 06:39:28 UTC
README
A powerful dependency injection container specifically designed for WordPress plugin development. This container provides advanced features like auto-wiring, service binding, configuration management, and service tagging to help you build maintainable and testable WordPress plugins.
Features
- 🚀 Dependency Injection: Automatic dependency resolution and injection
- 📦 Service Binding: Bind interfaces to implementations
- 🔧 Configuration Management: Built-in configuration handling with dot notation
- 🏷️ Service Tagging: Group and retrieve related services
- 💡 Auto-wiring: Automatic class instantiation and dependency resolution
- 🎯 Singleton Support: Register shared instances across your application
- 🔄 Alias System: Create shortcuts for your services
- 🎪 WordPress Integration: Designed specifically for WordPress plugin architecture
Installation
Install via Composer:
composer require byteever/container
Or add to your composer.json
:
{ "require": { "byteever/container": "^1.0" } }
Quick Start
Basic Usage
use ByteEver\Container\Container; // Create a container instance $container = Container::create(); // Bind a service $container->bind('logger', MyLogger::class); // Resolve the service $logger = $container->make('logger'); // Register an instance $container->instance('database', new Database($config)); // Get the instance $db = $container->get('database');
WordPress Plugin Integration
Important: For WordPress plugin development, you must pass the main plugin file path to extract plugin metadata.
// In your main plugin file use ByteEver\Container\Container; class MyPlugin { private Container $container; public function __construct() { // REQUIRED: Pass the main plugin file (__FILE__) $this->container = Container::create(__FILE__); $this->registerServices(); } private function registerServices(): void { // Register your plugin services $this->container->singleton('admin', Admin::class); $this->container->singleton('frontend', Frontend::class); $this->container->bind('api', API::class); } public function getContainer(): Container { return $this->container; } }
Configuration Management
The container includes a powerful configuration system with dot notation support:
$container = Container::create([ 'database' => [ 'host' => 'localhost', 'port' => 3306, 'credentials' => [ 'username' => 'admin', 'password' => 'secret' ] ], 'cache' => [ 'driver' => 'redis', 'ttl' => 3600 ] ]); // Get configuration values $host = $container->get_config('database.host'); // 'localhost' $username = $container->get_config('database.credentials.username'); // 'admin' $ttl = $container->get_config('cache.ttl', 1800); // 3600 (with default fallback) // Set configuration values $container->set_config('api.key', 'your-api-key'); $container->set_config('features.beta', true); // Check if configuration exists if ($container->has_config('database.credentials')) { // Configuration exists }
Service Binding
Basic Binding
// Bind a concrete class $container->bind('logger', FileLogger::class); // Bind with a closure $container->bind('mailer', function($container) { return new Mailer($container->get_config('smtp')); }); // Bind interface to implementation $container->bind(LoggerInterface::class, FileLogger::class);
Singleton Binding
// Register as singleton $container->singleton('database', Database::class); // Both calls return the same instance $db1 = $container->make('database'); $db2 = $container->make('database'); // $db1 === $db2 (true)
Instance Registration
// Register existing instance $logger = new Logger('/path/to/log'); $container->instance('logger', $logger); // Auto-instantiation (new feature!) $container->instance(Database::class); // Automatically creates and registers instance // Bulk registration $container->instance([ 'cache' => new RedisCache(), 'session' => new SessionManager() ]);
Auto-wiring
The container automatically resolves dependencies through constructor injection:
class UserService { public function __construct( private Database $database, private Logger $logger, private CacheInterface $cache ) {} } class Database { public function __construct(private string $host = 'localhost') {} } // Register dependencies $container->bind(CacheInterface::class, RedisCache::class); $container->instance('logger', new Logger()); // Auto-wiring in action - resolves all dependencies automatically $userService = $container->make(UserService::class);
Service Tagging
Group related services with tags:
// Tag services $container->tag('handlers', [ 'user_handler', 'post_handler', 'comment_handler' ]); // Or tag individually $container->bind('user_handler', UserHandler::class); $container->tag('handlers', 'user_handler'); // Get all services with a tag $handlers = $container->tagged('handlers'); foreach ($handlers as $handler) { $handler->process(); }
Aliases
Create convenient shortcuts for your services:
$container->bind(DatabaseInterface::class, MySQLDatabase::class); $container->alias(DatabaseInterface::class, 'db'); // Now you can use either $database = $container->make(DatabaseInterface::class); $database = $container->make('db'); // Same instance
WordPress-Specific Features
Plugin File Integration
// The container can extract plugin metadata $container = Container::create(__FILE__); // Pass your main plugin file // Access plugin information $pluginName = $container->get_config('name'); $version = $container->get_config('version'); $textDomain = $container->get_config('text_domain');
Hook Integration
class MyPlugin { public function __construct() { $this->container = Container::create(__FILE__); $this->registerHooks(); } private function registerHooks(): void { add_action('init', [$this, 'init']); add_action('admin_init', [$this, 'adminInit']); } public function init(): void { $frontend = $this->container->make('frontend'); $frontend->init(); } public function adminInit(): void { $admin = $this->container->make('admin'); $admin->init(); } }
Advanced Usage
Custom Service Providers
class DatabaseServiceProvider { public function register(Container $container): void { $container->singleton('database', function($container) { return new Database( $container->get_config('database.host'), $container->get_config('database.port'), $container->get_config('database.credentials') ); }); $container->alias('database', 'db'); } } // Register the service provider $provider = new DatabaseServiceProvider(); $provider->register($container);
Conditional Binding
// Bind different implementations based on environment if ($container->get_config('app.debug')) { $container->bind(LoggerInterface::class, DebugLogger::class); } else { $container->bind(LoggerInterface::class, ProductionLogger::class); }
Method Injection
// You can pass additional parameters when resolving $userService = $container->make(UserService::class, [ 'connection' => 'mysql-read-replica' ]);
API Reference
Container Methods
Creation
Container::create(array|string $config = [], string $namespace = __NAMESPACE__): static
Service Resolution
make(string $abstract, array $parameters = []): mixed
get(string $key, mixed $default = null): mixed
Service Binding
bind(string $abstract, Closure|string|null $concrete = null, bool $shared = false): self
singleton(string $abstract, Closure|string|null $concrete = null): self
instance(string|array $abstract, object $instance = null): self
Configuration
get_config(string $key, mixed $default = null): mixed
set_config(string $key, mixed $value): self
has_config(string $key): bool
Service Management
bound(string $abstract): bool
alias(string $abstract, string $alias): void
tag(string $tag, array|string $services): void
tagged(string $tag): array
flush(): void
Best Practices
1. Use Interfaces
// Good $container->bind(LoggerInterface::class, FileLogger::class); // Instead of $container->bind('logger', FileLogger::class);
2. Register Services Early
class MyPlugin { public function __construct() { $this->container = Container::create(__FILE__); $this->registerServices(); // Do this early $this->registerHooks(); } }
3. Use Service Providers for Complex Setup
class PluginServiceProvider { public function register(Container $container): void { // Group related service registrations $this->registerDatabase($container); $this->registerCache($container); $this->registerLogging($container); } }
4. Leverage Auto-wiring
// Let the container handle dependencies class AdminController { public function __construct( private UserRepository $users, private Logger $logger, private Validator $validator ) {} } // Just resolve - dependencies are auto-injected $controller = $container->make(AdminController::class);
Testing
The container makes testing easier by allowing dependency injection:
class UserServiceTest extends TestCase { public function testUserCreation(): void { $container = Container::create(); // Mock dependencies $mockDatabase = $this->createMock(Database::class); $mockLogger = $this->createMock(Logger::class); $container->instance('database', $mockDatabase); $container->instance('logger', $mockLogger); $userService = $container->make(UserService::class); // Test your service with mocked dependencies $this->assertInstanceOf(UserService::class, $userService); } }
Common Patterns
Plugin Architecture
// Main plugin class class MyAwesomePlugin { private Container $container; public function __construct() { $this->container = Container::create(__FILE__); $this->bootstrap(); } private function bootstrap(): void { // Register core services $this->registerCore(); // Register WordPress hooks $this->registerHooks(); // Initialize modules $this->initializeModules(); } private function registerCore(): void { $this->container->singleton('plugin', $this); $this->container->singleton('loader', HookLoader::class); $this->container->singleton('admin', AdminModule::class); $this->container->singleton('frontend', FrontendModule::class); $this->container->singleton('api', APIModule::class); } private function registerHooks(): void { $loader = $this->container->make('loader'); $loader->run(); } private function initializeModules(): void { if (is_admin()) { $this->container->make('admin')->init(); } else { $this->container->make('frontend')->init(); } } }
Requirements
- PHP 7.4 or higher
- WordPress 5.0 or higher (for WordPress-specific features)
Contributing
We welcome contributions! Please see our Contributing Guide for details.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- Documentation: Full Documentation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Changelog
See CHANGELOG.md for a list of changes.
ByteEver Container - Powering modern WordPress plugin development with clean, maintainable dependency injection.