Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Settings Container Laravel Package

chillerlan/php-settings-container

Lightweight settings container for PHP that decouples configuration logic from your application. Provides a SettingsContainerInterface with property-hook style access (for PHP < 8.4). Not a dependency injection container.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Immutable Configuration Container: Fits well in Laravel’s architecture for managing immutable, centralized application settings (e.g., replacing config() cache or environment variables). Avoids global state pollution by encapsulating settings in typed objects.
  • Trait-Based Extensibility: Complements Laravel’s modular design by allowing traits (e.g., from third-party libraries) to define custom logic for property access/modification without DI complexity.
  • Alternative to Laravel’s Config: Could replace config() for domain-specific settings (e.g., feature flags, API clients) where immutability is critical.
  • PHP 8.4+ Property Hooks: Leverages native PHP features for cleaner property access logic, reducing boilerplate compared to manual getters/setters.

Integration Feasibility

  • Low Coupling: No Laravel-specific dependencies; integrates via Composer. Can coexist with Laravel’s existing config() system or replace it selectively.
  • Serialization Support: Native JsonSerializable, Serializable interfaces align with Laravel’s caching (e.g., Redis, file-based) and API response needs.
  • Validation Hooks: Custom set_*/get_* methods enable runtime validation (e.g., sanitizing API keys), similar to Laravel’s Form Requests but at the config layer.

Technical Risk

  • PHP 8.4+ Dependency: Blocks use in older Laravel versions (pre-10.x). Requires PHP upgrade or polyfill (though property hooks are non-negotiable for full feature set).
  • Magic Methods: May conflict with Laravel’s magic methods (e.g., __get() in ArrayAccess traits). Mitigate by:
    • Prefixing custom methods (e.g., _get_foo()).
    • Using #[ThrowOnInvalidProperty] to fail fast on invalid access.
  • Immutability Tradeoffs: Immutable containers require reconstruction for updates, unlike Laravel’s mutable config() array. Workaround: Use a factory pattern to rebuild containers with new data.
  • Trait Composition: Complex trait interactions (e.g., method name collisions) may need refactoring. Test with phpstan using the provided rules-magic-access.neon.

Key Questions

  1. Use Case Scope:
    • Will this replace all Laravel config or only specific domains (e.g., third-party integrations)?
    • Does immutability justify the complexity vs. Laravel’s mutable config()?
  2. Migration Path:
    • How to backfill existing config() arrays into SettingsContainer instances?
    • Should we use a hybrid approach (e.g., SettingsContainer for immutable settings, config() for mutable ones)?
  3. Performance:
    • Will serialization/deserialization overhead impact high-throughput APIs?
    • How does it compare to Laravel’s cached config()?
  4. Testing:
    • How to mock SettingsContainer in unit tests (e.g., for dependency injection)?
    • Does it integrate with Laravel’s Testing facade?
  5. Error Handling:
    • Should ThrowOnInvalidProperty be enabled globally or per-container?
    • How to handle missing properties gracefully in production?

Integration Approach

Stack Fit

  • Laravel Ecosystem:
    • Replaces: config(), env(), or third-party config managers (e.g., vlucas/phpdotenv).
    • Complements: Works alongside Laravel’s service container (via traits) or as a standalone config layer.
    • Caching: Integrates with Laravel’s cache drivers via serialize()/unserialize() for persistent storage.
  • PHP Extensions:
    • Property Hooks (PHP 8.4+): Enables declarative property logic (e.g., @property-write for validation).
    • Traits: Allows modular configuration (e.g., use DatabaseSettingsTrait, use ApiClientSettingsTrait).

Migration Path

  1. Phase 1: Pilot Domain
    • Start with a non-critical module (e.g., logging, analytics) to test immutability and trait composition.
    • Example:
      class AppSettings extends SettingsContainerAbstract {
          use LoggingSettingsTrait, AnalyticsSettingsTrait;
      }
      
  2. Phase 2: Hybrid Integration
    • Wrap Laravel’s config() in a SettingsContainer for immutable access:
      $settings = new SettingsContainer([
          'app.name' => config('app.name'),
          'database.connections' => config('database.connections'),
      ]);
      
    • Use fromJSON() to load from Laravel’s cached config files.
  3. Phase 3: Full Replacement
    • Replace config() calls with SettingsContainer instances in services.
    • Update providers to initialize containers:
      public function register() {
          $this->app->singleton(AppSettings::class, fn() => new AppSettings(config('app.settings')));
      }
      

Compatibility

  • Laravel Services:
    • Bind containers to the service container for DI:
      $this->app->bind(AppSettings::class, fn() => new AppSettings($this->app['config']['app.settings']));
      
    • Use in controllers/services:
      public function __construct(private AppSettings $settings) {}
      
  • Environment Variables:
    • Load from .env via fromIterable() or a custom trait:
      trait EnvSettingsTrait {
          public function loadFromEnv(): static {
              return $this->fromIterable($_ENV);
          }
      }
      
  • Validation:
    • Integrate with Laravel’s Validator via custom set_* methods:
      protected function set_apiKey(string $value): void {
          if (!Validator::make(['key' => $value], ['key' => 'required|string'])->passes()) {
              throw new \InvalidArgumentException('Invalid API key');
          }
          $this->apiKey = $value;
      }
      

Sequencing

  1. Upgrade PHP: To 8.4+ for property hooks (or use polyfills for partial support).
  2. Add Composer Dependency:
    composer require chillerlan/php-settings-container ^3.0
    
  3. Create Base Container:
    namespace App\Config;
    use Chillerlan\SettingsContainer\SettingsContainerAbstract;
    
    class AppSettings extends SettingsContainerAbstract {
        protected string $appName;
        protected array $database;
        // ...
    }
    
  4. Register in Service Provider:
    $this->app->singleton(AppSettings::class, fn() => new AppSettings(config('app.settings')));
    
  5. Replace Config Access:
    • Old: config('app.name')
    • New: $settings->appName (injected via constructor).
  6. Add Traits for Complex Logic:
    trait DatabaseSettingsTrait {
        protected string $defaultConnection;
        protected array $connections;
    
        protected function DatabaseSettingsTrait(): void {
            $this->defaultConnection = $this->connections['mysql']['default'] ?? 'mysql';
        }
    }
    

Operational Impact

Maintenance

  • Pros:
    • Type Safety: PHPStan/Psalm can analyze property access (use the provided rules-magic-access.neon).
    • Immutability: Reduces side effects in config changes (e.g., no accidental overrides).
    • Trait Isolation: Easier to update individual settings modules (e.g., LoggingSettingsTrait) without touching core config.
  • Cons:
    • Reconstruction Overhead: Updating settings requires creating a new container instance (vs. Laravel’s mutable config()).
    • Debugging: Magic methods may obscure property access in stack traces. Use #[ThrowOnInvalidProperty] to fail fast.
    • Tooling: IDE autocompletion may lag behind dynamic property access (mitigate with PHPDoc @property).

Support

  • Learning Curve:
    • Developers must adapt to immutability and trait-based composition (vs. Laravel’s array-based config).
    • Provide internal docs with:
      • Examples of trait integration.
      • Migration guides from config() to SettingsContainer.
  • Error Handling:
    • Centralize error handling in a base trait:
      trait ErrorHandlingTrait {
          protected function handleInvalidProperty(string $property): void {
              throw new \RuntimeException("Invalid setting: {$property}");
          }
      }
      
    • Log property access attempts for observability.

Scaling

  • Performance:
    • Serialization: Benchmark toArray()/fromIterable() vs. Laravel’s config() caching. Consider memoization for read-heavy workloads.
    • Memory: Immutable containers may reduce memory churn if cached aggressively (e.g., in Laravel’s cache).
  • Horizontal Scaling:
    • Stateless containers work well in distributed environments (e.g., microservices).
    • For shared config, use a centralized cache (e.g., Redis) with serialize()/unserialize().

Failure Modes

Failure Scenario Impact Mitigation
Invalid property access Silent null or exception Enable #[ThrowOnInvalidProperty] globally.
Trait method
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder
psr/simple-cache-implementation