GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - php-internal/container: Lightweight PSR-11 container for CLI tools

BranchesTags
Open more actions menu

Latest commit

 

History

72 Commits
72 Commits

Folders and files

NameName
Last commit message
Last commit date
.github
.github
 
 
src
src
 
 
tests
tests
 
 
tools
tools
 
 
.editorconfig
.editorconfig
 
 
.gitattributes
.gitattributes
 
 
.gitignore
.gitignore
 
 
.php-cs-fixer.dist.php
.php-cs-fixer.dist.php
 
 
CHANGELOG.md
CHANGELOG.md
 
 
LICENSE.md
LICENSE.md
 
 
README.md
README.md
 
 
composer.json
composer.json
 
 
infection.json
infection.json
 
 
psalm.xml
psalm.xml
 
 
skills.json
skills.json
 
 
testo.php
testo.php
 
 

Repository files navigation

Container

A lightweight PSR-11 container for CLI tools

Support on Boosty

Vibe Index Psalm Level Type Coverage codecov Mutation testing badge


A small PSR-11 container for command-line tools and other short-lived PHP processes: autowiring, a handful of bindings and deterministic cleanup without a full-blown DI framework. No compilation, no config files, no lazy proxies, nothing to set up beyond new ObjectContainer(). It was born in Trap, grew up in DLoad and Testo, and is extracted here so all of them can share one implementation.

What it does:

  • Resolves classes by constructor autowiring through yiisoft/injector; resolved services are cached.
  • Accepts bindings as a factory closure, an alias class name or predefined constructor arguments.
  • Creates objects that implement Factoriable through their static create() method with autowired parameters.
  • Passes every resolved object through registered Inflectors before it is cached.
  • Opens nested scopes: services resolved inside a scope live only until the scope closes.
  • Destroys managed services on destroy(), see internal/destroy.

Installation

composer require internal/container

PHP Latest Version on Packagist License Total Downloads

Usage

use Internal\Container\Container;
use Internal\Container\ObjectContainer;

$container = new ObjectContainer();

// Autowired on first request, cached afterwards
$downloader = $container->get(Downloader::class);

// Factory binding
$container->bind(Logger::class, static fn(Container $c) => new Logger($c->get(OutputInterface::class)));

// Alias binding: an interface resolves to a concrete class
$container->bind(ClockInterface::class, SystemClock::class);

// Constructor arguments binding
$container->bind(HttpClient::class, ['timeout' => 30]);

// Register an existing instance; `destroy: true` hands its lifecycle over to the container
$container->set($output, OutputInterface::class, destroy: true);

// A fresh instance that is not cached
$request = $container->make(Request::class, ['uri' => '/']);

Factoriable

A class that needs custom construction implements Factoriable and exposes a static create(). The container calls it with autowired parameters instead of the constructor.

use Internal\Container\Factoriable;

final class Config implements Factoriable
{
    private function __construct(private readonly Logger $logger) {}

    public static function create(Logger $logger): self
    {
        return new self($logger);
    }
}

Inflectors

An Inflector sees every object right after it is resolved and may replace or configure it.

use Internal\Container\Container;
use Internal\Container\Inflector;

$container->addInflector(new class implements Inflector {
    public function inflect(object $object, Container $container): object
    {
        $object instanceof LoggerAwareInterface and $object->setLogger($container->get(Logger::class));
        return $object;
    }
});

Scopes

scope() runs a closure against a child state. Bindings are inherited, cached services are cloned into the scope (readonly objects and enums are shared as is), and everything resolved inside is destroyed when the closure returns. The parent state is left untouched.

$result = $container->scope(static function (Container $scoped): Result {
    $scoped->set(new SuiteConfig(...));

    return $scoped->get(SuiteRunner::class)->run();
});

Scopes are fiber-aware: a scope opened outside an event loop is the active one for everything that runs on the loop under it. Opening a scope inside a loop-driven fiber and suspending within it is not supported.

Testing

composer test

About

Lightweight PSR-11 container for CLI tools

Topics

autowiringclicontainerdependency-injectionphppsr-11

Resources

Readme
BSD-3-Clause license

Code of conduct

Code of conduct
Activity
Custom properties

Stars

1 star

Watchers

0 watching

Forks

0 forks
Report repository

Releases

Packages

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.