Weave 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

Service Provider Laravel Package

crodas/service-provider

A lightweight PHP service-provider library for registering, configuring, and bootstrapping application services through a simple, container-friendly API. It keeps dependency wiring modular and maintainable, making service initialization easier to organize in PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

crodas/service-provider is a tiny, single-author DI/configuration container. It is not a Laravel package — there is no service provider, no facade, no config file. You pull it in directly and use it as a standalone container, or wrap it yourself.

composer require crodas/service-provider

First steps, in order:

  1. Read the repo README and src/ before anything else. With 2 stars and zero dependents, the README is the spec. Confirm the exact class name of the container base class — the package exposes a provider class you extend, and the FQCN matters for extends and for any type-hints you inject. Don't trust blog posts; trust vendor/crodas/service-provider/src.
  2. Create a provider class that extends the package's base container. Register your bindings in its constructor or an init-style method using closures.
  3. Resolve services out of that container and pass them into your entry point (a CLI script, an artisan command, a controller action).

First real use case: a standalone CLI/bootstrap — a script or queue worker that needs a handful of wired-together services (a DB wrapper, a mailer, a repository) without booting the whole framework. That is where this package fits naturally.

// Confirm the base class name against the repo before relying on this.
use Crodas\ServiceProvider\Container;

class AppContainer extends Container
{
    public function __construct(array $config = [])
    {
        parent::__construct($config);

        $this->register('db', fn ($c) => new PDO($c['config']['dsn']));
        $this->register('userRepo', fn ($c) => new UserRepository($c->get('db')));
    }
}

$c = new AppContainer(require __DIR__.'/config.php');
$repo = $c->get('userRepo');

Implementation Patterns

Closure-per-service registration. The bread-and-butter pattern: every service is a closure that receives the container and returns the built object. Keep closures pure and free of side effects — they may be re-invoked if the container isn't caching singletons.

Singleton vs. factory discipline. Small containers often re-instantiate on every get(). If the package distinguishes them (some crodas releases use a flag on the registration call), use singletons for stateful things (DB connections, loggers) and factories for value objects. Verify this in src/ — it's the single most important behavioral detail for day-to-day use.

Annotation-based wiring (crodas' house style). crodas packages lean on docblock annotations via his Notoj parser. If this package does the same, you'll declare dependencies with @Inject-style tags on properties or constructor params. That is convenient for demos and painful in production — always pair it with an annotation cache, or pre-warm the container at deploy time.

Bridging into Laravel. If you must use it inside an app, do it in a register() method of a real Laravel service provider and bind the instance as a singleton:

public function register(): void
{
    $this->app->singleton(AppContainer::class, function ($app) {
        return new AppContainer(config('services.legacy'));
    });
    $this->app->alias(AppContainer::class, 'legacy.container');
}

Then inject AppContainer into controllers/commands. Do not try to make Laravel's container delegate to it globally — you'll fight app(), facades, and Octane.

Config merge pattern. Treat the constructor array as the only config source. Read it once, validate required keys eagerly (fail fast at bootstrap), and pass plain values into closures rather than having closures re-read $c['config'] at resolution time.

Testing integration. Because services are closures, you can swap any binding with a fake in a setUp() — that's the main advantage over a full framework in a CLI context.

Gotchas and Tips

  • Abandonment risk is the headline gotcha. 2 stars, 0 dependents, no release cadence. Pin an exact version in composer.json and vendor-review the source before shipping. Have a migration plan: every binding you write should be a plain closure that could move to Laravel's $this->app->bind() in an afternoon.
  • Name collision. ServiceProvider is the most overloaded class name in Laravel (Illuminate\Support\ServiceProvider). You will get import conflicts and IDE confusion. Always alias on import: use Crodas\ServiceProvider\Container as LegacyContainer;.
  • PSR-11 compliance is not guaranteed. Check for Psr\Container\ContainerInterface. If it's absent, none of the standard get()/has() interop tooling works, and you cannot type-hint ContainerInterface in shared code.
  • No autowiring by default. Most micro-containers require explicit registration — no constructor reflection resolution. If the package does autowire, know its limits (interface params, scalar params, circular refs) before you rely on it in a controller constructor.
  • Annotation parsing cost. If injection is annotation-driven, the first request pays for reflection + docblock parsing on every class. Cache the resolved map to a file in production; regenerate only when source files change.
  • No scoped/contextual bindings. Don't expect request-scoped instances or per-consumer contextual resolution. Build the container once per process, and in long-running workers (Octane, Swoole, queue daemons) be explicit about which bindings must be reset between jobs.
  • Debugging: when get() fails, the exception is often a bare "service not found" with no key list. Add your own has() check or a small dumpServiceKeys() helper during development — it saves hours.
  • Extension points are thin by design. The realistic extension surface is subclassing the container and overriding the resolver. There's no middleware, tag system, or compiler pass. Don't invent one.
  • Upgrade path: if you're starting greenfield in a Laravel codebase, skip this package entirely — Illuminate\Container already does everything here, is battle-tested, PSR-11 compliant, and has autowiring. Reserve this package for isolated CLI tooling or code that predates the framework.
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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core