๐Ÿš€ PHP Service Container with fast and cachable dependency injection.

Overview

ClanCats Container

A PHP Service Container featuring a simple meta-language with fast and compilable dependency injection.

Build Status Packagist Packagist GitHub release

Requires PHP >= 7.0

Pros:

  • Minimal overhead and therefore very fast.
  • Has no additional dependencies.
  • In production serving millions of requests every day.
  • Singleton and Factory service resolvers.
  • Metadata system allowing very intuitive service lookups.
  • A container builder allowing to compile / serialize your service definitions.
  • Container files a simple language to define your services and manage your application config.
  • Composer integration, allowing you to import service definitions from different packages.
  • Lazy service providers for big and dynamic class graphs.

Things you might not like:

  • Container allows only named services.
  • Currently no auto wiring support.
  • Currently no IDE Support for container files.
  • Having a meta-language might not meet everyone's taste.

Table of Contents

Performance

This package might seem very heavy for a service container, but after a short warmup, the compiled container is blazing fast and has almost no overhead (3 classes/files). Binding and resolving services dynamically is slower but still won't impact performance in a real-world application.

Installation

The container follows PSR-4 autoloading and can be installed using composer:

$ composer require clancats/container

Syntax Highlighting

I've created a basic tmLanguage definition here: https://github.com/ClanCats/container-tmLanguage

Documentation ๐Ÿ’ก

The full documentation can be found on clancats.io

Quick Start โšก๏ธ

Following is just a rough example, a much more detailed and explained guide can be found here: Getting Started

Setup

Our target directory structure will look like this:

app.php
app.ctn
composer.json
cache/ # make sure this is writable
src/
  Human.php
  SpaceShip.php

Services

To demonstrate how to use this service container we need to create two classes a SpaceShip and a Human.

Create a new php file src/Human.php:

class Human
{
    public $name;

    public function setName(string $name) {
        $this->name = $name;
    }
}

Create another php file src/SpaceShip.php:

class SpaceShip
{
    protected $captain; // every ship needs a captain!

    public function __construct(Human $captain) {
        $this->captain = $captain;
    }

    public function ayeAye() {
        return 'aye aye captain ' . $this->captain->name;
    }
}

Container file

A container file allows you to bind your services & parameters using a simple meta-language.

Note: This feature is entirely optional if you prefer binding your services in PHP itself read: Service Binding

Create a new file called app.ctn in your applications root folder.

@malcolm: Human
    - setName('Reynolds')

@firefly: SpaceShip(@malcolm)

Container factory

Now we need to parse the container file and compile it as a new class. For this task, we create the app.php file. There you need to require the composer autoloader and require your source files or configure composer to autoload the classes from the src/ directory.

require "vendor/autoload.php";

// for the consistency of the example I leave this here 
// but I strongly recommend to autolaod your classes with composer.
require "src/SpaceShip.php";
require "src/Human.php";

$factory = new \ClanCats\Container\ContainerFactory(__DIR__ . '/cache');

$container = $factory->create('AppContainer', function($builder)
{
    // create a new container file namespace and parse our `app.ctn` file.
    $namespace = new \ClanCats\Container\ContainerNamespace();
    $namespace->parse(__DIR__ . '/app.ctn');

    // import the namespace data into the builder
    $builder->importNamespace($namespace);
});

Note: Make sure the ../cache directory is writable.

The variable $container contains now a class instance named AppContainer.

echo $container->get('firefly')->ayeAye(); // "aye aye captain Reynolds"

Usage Examples

App Config with Environment

Container parameters are nothing more than values that are globally available in your container. We use them to store most static config values and also to handle different environments.

For this, we usually create two files. In this example:

  • config.ctn The main configuration file.
  • config.ctn.env Environment specific overrides.

config.ctn:

// default environment
:env: 'stage'

// debug mode
:debug: false

// Firewall whitelist
:firewall.whitelisted_ips: {
    '127.0.0.1': 'Local',
    '1.2.3.4': 'Some Office',
    '4.3.2.1': 'Another Office',
}

// application name
:app.name: 'My Awesome application'

import config.env

config.ctn.env:

override :env: 'dev'
override :debug: true

// Firewall whitelist
override :firewall.whitelisted_ips: {
    '127.0.0.1': 'Local',
    '192.168.33.1': 'MyComputer',
}

In PHP these values are then accessible as parameters. For this, to work you need to configure the correct import paths in your container namespace. You find an example of that in the Example App.

echo $container->getParameter('app.name'); // 'My Awesome application'
echo $container->getParameter('env'); // 'dev'
echo $container->getParameter('debug'); // true

Aliases / Services Definitions / Parameters Example

# Parameters can be defined erverywhere
:pipeline.prefix: 'myapp.'

// you can define aliases to services
@pipeline.queue: @queue.redis
@pipeline.storage: @db.repo.pipeline.mysql

// add function calls that will be run directly after construction of the service
@pipeline: Pipeline\PipelineManager(@pipeline.queue, @pipeline.storage, @pipeline.executor)
  - setPrefix(:pipeline.prefix)
  - bind(@pipeline_handler.image.downloader)
  - bind(@pipeline_handler.image.process)

@pipeline_handler.image.downloader: PipelineHandler\Images\DownloadHandler(@client.curl)
@pipeline_handler.image.process: PipelineHandler\Images\ProcessHandler(@image.processor, { 
  'temp_dir': '/tmp/', 
  'backend': 'imagick'
})

HTTP Routing using Metadata

Your can use the container metadata to define routes directly with your service definitions:

@controller.dashboard.home: App\Controller\Dashboard\HomepageAction
    = route: {'GET'}, '/dashboard/home'

@controller.dashboard.sign_in: App\Controller\Dashboard\SignInAction
    = route: {'GET', 'POST'}, '/dashboard/signin'

@controller.dashboard.sign_out: App\Controller\Dashboard\SignOutAction
    = route: {'GET'}, '/logout'

@controller.dashboard.client: App\Controller\Dashboard\ClientDetailAction
    = route: {'GET'}, '/dashboard/clients/me'
    = route: {'GET'}, '/dashboard/clients/{clientId}'

Now obviously this is depending on your routing implementation. You are able to fetch all services with a routing definition like so:

Example using FastRoute:

$dispatcher = \FastRoute\cachedDispatcher(function(RouteCollector $r) use($container)
{
    foreach($container->serviceNamesWithMetaData('route') as $serviceName => $routeMetaData)
    {
        // an action can have multiple routes handle all of them
        foreach($routeMetaData as $routeData)
        {
            $r->addRoute($routeData[0], $routeData[1], $serviceName);
        }
    }
}, [
    'cacheFile' => PATH_CACHE . '/RouterCache.php',
    'cacheDisabled' => $container->getParameter('env') === 'dev',
]);

Eventlisteners using Metadata

Just like with the routing you can use the meta data system to define eventlisteners:

@signal.exception.http404: App\ExceptionHandler\NotFoundExceptionHandler
  = on: 'http.exception', call: 'onHTTPException'

@signal.exception.http400: App\ExceptionHandler\BadRequestExceptionHandler
  = on: 'http.exception', call: 'onHTTPException'

@signal.exception.http401: App\ExceptionHandler\UnauthorizedAccessExceptionHandler
  = on: 'http.exception', call: 'onHTTPException'

@signal.bootstrap_handler: App\Bootstrap
    = on: 'bootstrap.pre', call: 'onBootstrapPre'
    = on: 'bootstrap.post', call: 'onBootstrapPost'

And then in your event dispatcher register all services that have the matching metadata.

The following example shows how the implementation could look like. Copy pasting this will not just work.

foreach($container->serviceNamesWithMetaData('on') as $serviceName => $signalHandlerMetaData)
{
    // a action can have multiple routes handle all of them
    foreach($signalHandlerMetaData as $singalHandler)
    {
        if (!is_string($singalHandler[0] ?? false)) {
            throw new RegisterHandlerException('The signal handler event key must be a string.');
        }

        if (!isset($singalHandler['call']) || !is_string($singalHandler['call'])) {
            throw new RegisterHandlerException('You must define the name of the function you would like to call.');
        }

        $priority = $singalHandler['priority'] ?? 0;

        // register the signal handler
        $eventdispatcher->register($singalHandler[0], function(Signal $signal) use($container, $singalHandler, $serviceName)
        {
            $container->get($serviceName)->{$singalHandler['call']}($signal);
        }, $priority);
    }
}

Logging handler discovery

Or maybe you have a custom framework that comes with a monolog logger and you want to make it easy to add custom log handlers per integration:

/**
 * Log to Graylog
 */
:gelf.host: 'monitoring.example.com'
:gelf.port: 12201

@gelf.transport: Gelf\Transport\UdpTransport(:gelf.host, :gelf.port)
@gelf.publisher: Gelf\Publisher(@gelf.transport)
@logger.error.gelf_handler: Monolog\Handler\GelfHandler(@gelf.publisher)
  = log_handler

/**
 * Also send a slack notification 
 */
@logger.,error.slack_handler: Example\MyCustom\SlackWebhookHandler('https://hooks.slack.com/services/...', '#logs')
    = log_handler

And your framework can simply look for services exposing a log_handler meta key:

// gather the log handlers
$logHandlerServices = array_keys($container->serviceNamesWithMetaData('log_handler'));

// bind the log hanlers
foreach($logHandlerServices as $serviceName) {
    $logger->pushHandler($container->get($serviceName));
}

Container File Syntax

Container files are written in a very simple meta language.

Types

The language supports the following scalar types:

  • Strings Single and double quoted.
    'hello' & "world"
  • Numbers float / double, int.
    3.14, 42
  • Booleans
    true and false.
  • Null
    null
  • Arrays list and associative.
    {'A', 'B', 'C'}, {'A': 10, 'B': 20}

Numbers

Container files do not differentiate between different number types because it would be an unnecessary overhead, we forward that job directly to PHP.

42 # Int
42.01 # Float
-42.12345678912345 # Double

That means that also the floating point precision is handled by PHP. All values are interpreted means large doubles might be stored rounded.

Strings

Strings must always be encapsulated with a single ' or double " quote. This serves mainly a comfort purpose when having many quotes inside your string not having to escape them all.

Escaping of special characters works just the usual way.

:say: 'Hello it\'s me!'`

Beloved or Hated emojis will also work just fine.

:snails: '๐ŸŒ๐ŸŒ๐ŸŒ'

Booleans and Null

There is not much to say about them:

:nothing: null
:positive: true
:negative: false

Arrays

It's important to notice that all arrays are internally associative. When defining a simple list the associative key is automatically generated and represents the index of the item.

This means that the array {'A', 'B'} equals {0: 'A', 1: 'B'}.

Arrays can be defined multidimensional:

{
    'title': 'Some catchy title with Star Wars',
    'tags': {'top10', 'movies', 'space'},
    'body': 'Lorem ipsum ...',
    'comments': 
    {
        {
            'text': 'Awesome!',
            'by': 'Some Dude',
        }
    }
}

Parameters

Parameters or configuration values can also be defined inside the container files.

A parameter is always prefixed with a : character.

:database.hostname: "production.db.example.com"
:database.port: 7878
:database.cache: true

Service Definition

A service definition is always named and must be prefixed with a @ character.

## <service name>: <class name>
@log.adapter: FileAdapter

The class name can contain the full namespace.

@log.adapter: Acme\Log\FileAdapter

Constructor

Constructor arguments can be passed after the class name.

@dude: Person("Jeffery Lebowski")
Referenced arguments

Arguments can reference a parameter or service.

:name: 'Jeffery Lebowski'

@dude: Person(:name)
@mysql: MySQLAdapter('localhost', 'root', '')

@repository.posts: Repositories/Post(@mysql)

Method calls

Method calls can be assigned to a service definition.

@jones: Person('Duncan Jones')
@sam: Person('Sam Rockwell')

@movie.moon: Movie('Moon')
  - setDirector(@jones)
  - addCast(@sam)
  - setTags({'Sci-fi', 'Space'})

Service metadata

Metadata can be assigned to every service definition.

Its then possible to fetch the services matching a metadata key.

@controller.auth.sign_in: Controller\Auth\SignInController(@auth)
  = route: {'GET', 'POST'}, '/signin'

The metadata key is always a vector / array so you can add multiple of the same type:

@controller.auth.sign_in: Controller\Auth\SignInController(@auth)
  = route: {'GET', 'POST'}, '/signin'
  = tag: 'users'
  = tag: 'auth'

The elements inside the metadata definition can have named keys:

@app.bootstrap: Bootstrap()
  = on: 'app.start' call: 'onAppStart'

Service Updates

It is possible to update already defined services with more construction calls and metadata. This is quite handy to organize large amount of dependencies with a dynamic lookups.

You could for example define your logger in one file.

@logger.main: Acme\Logger

And add observers using a construction call where you need them.

@logger.observers.email_devs: Acme\EmailLogObserver('[email protected]')
@logger.observers.email_support: Acme\EmailLogObserver('[email protected]')

@logger.main
  - addObserver(@logger.observers.email_devs)
  - addObserver(@logger.observers.email_support)

The same is also true for metadata.

@controller.homepage: Controller\Homepage
  = on: '/homepage'


// also show homepage on root
@controller.homepage
  = on: '/'

Imports

Other container files can be imported from the container namespace.

import config
import app/dashboard
import app/user
import app/shop

Overriding

Services and Parameters have been explicit overwritten if they have already been defined.

:ship: 'Star Destroyer'

override :ship: 'X-Wing'

Example App

This should showcase a possible structure of an application build using the CCContiner. This is a simplified version of what we use in our private service framework.

Folder structure:

# The main entry point for our container application
app.ctn

# A per environment defined config. This file
# is being generated by our deployment process 
# individually for each node.
app.ctn.env 

# We like to but all other container files in one directory
app/
  # Most configuration parameters go here
  config.ctn

  # Command line commands are defined here
  commands.ctn

  # Application routes (HTTP), actions and controllers 
  routes.ctn

  # General application services. Depending on the size of 
  # the project we split the services into more files to keep
  # things organized. 
  services.ctn

# PHP Bootstrap
bootstrap.php

# Composer file
composer.json

# A writable directory for storing deployment 
# depndent files.
var/
  cache/

# PHP Source 
src/
  Controller/
    ListBlogPostController.php
    GetBlogPostController.php

  Commands/
    CreateUserCommand.php

  Servies/
    UserService.php
    BlogService.php

Bootstrap (Container Builder)

This container builder does a few things:

  • Imports container namespaces from packages installed using composer.
  • Scans the ./app directory for ctn files.
  • Adds the env container file to the namespace.
<?php 
if (!defined('DS')) { define('DS', DIRECTORY_SEPARATOR); }

define('PATH_ROOT',         __DIR__);
define('PATH_CACHE',        PATH_ROOT . DS . 'var' . DS . 'cache');
define('PATH_APPCONFIG',    PATH_ROOT . DS . 'app');

$factory = new \ClanCats\Container\ContainerFactory(PATH_CACHE);

$container = $factory->create('AppContainer', function($builder)
{
    $importPaths = [
        'app.env' => PATH_ROOT . '/app.ctn.env',
    ];

    // find available container files
    $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(PATH_APPCONFIG));

    foreach ($rii as $file) 
    {
        // skip directories
        if ($file->isDir()) continue;

        // skip non ctn files
        if (substr($file->getPathname(), -4) !== '.ctn') continue;

        // get the import name
        $importName = 'app' . substr($file->getPathname(), strlen(PATH_APPCONFIG), -4);

        // add the file
        $importPaths[$importName] = $file->getPathname();
    }

    // create a new container file namespace and parse our `app.ctn` file.
    $namespace = new \ClanCats\Container\ContainerNamespace($importPaths);
    $namespace->importFromVendor(PATH_ROOT . '/vendor');

    // start with the app file
    $namespace->parse(__DIR__ . '/app.ctn');

    // import the namespace data into the builder
    $builder->importNamespace($namespace);
});

App Container Files

The first file app.ctn has mainly one job. That is simply to include other files and therefore define the order they are being read.

app.ctn:

/**
 * Import the configuration
 */
import app/config

/**
 * Import the services
 */
import app/services

/**
 * Import the actions & routes
 */
import app/routes

/**
 * Import the commands
 */
import app/commands

/**
 * Load the environment config last so it is
 * able to override most configs.
 */
import app.env

ToDo / feature whishlist

  • Container Files
    • Metadata support
    • Array Support
    • Alias Support
    • Container file Namespace support
    • Autowiring by "using trait"
    • Autowiring by "instance of"
    • Autowiring by "has method"
    • Property injection
    • Parameter concatination
    • Input Parameters (used for env detection)
    • [ั…] Late service override (allow for adding meta or calls)
    • macros
  • Container
    • Metadata support
    • Property injection

Credits

License

The MIT License (MIT). Please see License File for more information.

You might also like...
DI Container (PSR-11)

My DI Container It's my own implementation PSR-11 Container Interface. Installation composer require scruwi/container Init $container = new Container(

This repository holds all interfaces related to PSR-11 (Container Interface).

Container interface This repository holds all interfaces related to PSR-11 (Container Interface). Note that this is not a Container implementation of

Extensible DI container for Symfony2
Extensible DI container for Symfony2

This package contains an implementation of the Symfony 2 DI container that can be extended using other DI containers (from other frameworks).

The DependencyInjection component allows you to standardize and centralize the way objects are constructed in your application.

DependencyInjection Component The DependencyInjection component allows you to standardize and centralize the way objects are constructed in your appli

Adapters for PHP framework containers to an interoperable interface

Acclimate - Container Adapters Get Acclimated! Use any third-party dependency injection containers and service locators in your code by adapting them

๐Ÿ’Ž Flexible, compiled and full-featured Dependency Injection Container with perfectly usable autowiring and support for all new PHP 7 features.

Nette Dependency Injection (DI) Introduction Purpose of the Dependecy Injection (DI) is to free classes from the responsibility for obtaining objects

Twittee is the smallest, and still useful, Dependency Injection Container in PHP

What is Twittee? Twittee is the smallest, and still useful, Dependency Injection Container in PHP; it is also probably one of the first public softwar

A small PHP dependency injection container

Pimple Caution! Pimple is now closed for changes. No new features will be added and no cosmetic changes will be accepted either. The only accepted cha

PSR-11 compatible Dependency Injection Container for PHP.

bitexpert/disco This package provides a PSR-11 compatible, annotation-based dependency injection container. Have a look at the disco-demos project to

The dependency injection container for humans
The dependency injection container for humans

layout home PHP-DI is a dependency injection container meant to be practical, powerful, and framework-agnostic. Read more on the website: php-di.org G

Small but powerful dependency injection container

Container (Dependency Injection) This package is compliant with PSR-1, PSR-2, PSR-4 and PSR-11. If you notice compliance oversights, please send a pat

Dependency Injection System

Aura.Di A serializable dependency injection container with constructor and setter injection, interface and trait awareness, configuration inheritance,

Dependency Injection System

Aura.Di A serializable dependency injection container with constructor and setter injection, interface and trait awareness, configuration inheritance,

Provide a module to industrialize API REST call with dependency injection using Guzzle library
Provide a module to industrialize API REST call with dependency injection using Guzzle library

Zepgram Rest Technical module to industrialize API REST call with dependency injection using Guzzle library. Provides multiple features to make your l

Yii Dependency Injection PSR-11 compatible

Yii Dependency Injection PSR-11 compatible dependency injection container that is able to instantiate and configure classes resolving dependencies. Fe

Dictionary of attack patterns and primitives for black-box application fault injection and resource discovery.

FuzzDB was created to increase the likelihood of finding application security vulnerabilities through dynamic application security testing. It's the f

Automatic SQL injection and database takeover tool
Automatic SQL injection and database takeover tool

sqlmap sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of

Application with SQL Injection vulnerability and possible privilege escalation
Application with SQL Injection vulnerability and possible privilege escalation

Application with SQL Injection vulnerability and possible privilege escalation. Free vulnerable app for ethical hacking / penetration testing training.

Comments
  • Added Support for Service Updates

    Added Support for Service Updates

    It is possible to update already defined services with more construction calls and metadata. This is quite handy to organize large amount of dependencies with a dynamic lookups.

    You could for example define your logger in one file.

    @logger.main: Acme\Logger
    

    And add observers using a construction call where you need them.

    @logger.observers.email_devs: Acme\EmailLogObserver('[email protected]')
    @logger.observers.email_support: Acme\EmailLogObserver('[email protected]')
    
    @logger.main
      - addObserver(@logger.observers.email_devs)
      - addObserver(@logger.observers.email_support)
    

    The same is also true for metadata.

    @controller.homepage: Controller\Homepage
      = on: '/homepage'
    
    
    // also show homepage on root
    @controller.homepage
      = on: '/'
    
    opened by mario-deluna 0
  • question: why do you use strings like 'logger'

    question: why do you use strings like 'logger'

    Hi, I saw in the documentation that you use something like $container->get('logger'); ... why do you not use the Interface-Class-Name as key, or at least a constant, is there a technical reason?

    opened by voku 0
Releases(v1.3.2)
  • v1.3.2(Oct 16, 2022)

    This hotfix only changes the import name when scanning a directory for ctn files.

    On windows they would use the windows filesystem directory separator, which is a backslash. The import names should not depend on the platform so we replace the backslashes always with forward ones in import names.

    Full Changelog: https://github.com/ClanCats/Container/compare/v1.3.1...v1.3.2

    Source code(tar.gz)
    Source code(zip)
  • v1.3.1(May 10, 2022)

    What's Changed

    This release adds support for class names to the container language.

    Example

    @driver_manager: MyApp\Drivers\Manager
        - bind('main', MyApp\Drivers\MainDriver::class)
        - bind('second', MyApp\Drivers\AnotherDriver::class)
    

    Class names can be used the same way normal values can be. Internally they are simply converted to a string:

    :some_class: Something\Somewhere::class
    
    :or_in_array: {
        ClassA::class, 
        ClassB::class
    }
    
    • v1.3.1 by @mario-deluna in https://github.com/ClanCats/Container/pull/9

    Full Changelog: https://github.com/ClanCats/Container/compare/v1.3.0...v1.3.1

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Apr 22, 2022)

    What's Changed

    • Fixed error handling displaying incorrect line number when having large comments in file.
    • Added support to report the file in which a syntax error occurred.
    • Strict type hinting throughout the code.
    • Removed support for PHP7.1 til 7.3
    • Migrated from Travis.CI to Github Actions
    • Added PHPStan including a fix for all issues for lvl8.

    Full Changelog: https://github.com/ClanCats/Container/compare/v1.2.2...v1.3.0

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2(Oct 15, 2020)

    This small update allows you to finally use the resolver methods directly. The resolver methods are generated when a container is compiled. The methods have the the return type their dependency which helps your IDE to help you.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Aug 14, 2020)

    This release introduces the ability to update service definitions after they have been defined.

    Service Updates

    It is possible to update already defined services with more construction calls and metadata. This is quite handy to organize large amount of dependencies with a dynamic lookups.

    You could for example define your logger in one file.

    @logger.main: Acme\Logger
    

    And add observers using a construction call where you need them.

    @logger.observers.email_devs: Acme\EmailLogObserver('[email protected]')
    @logger.observers.email_support: Acme\EmailLogObserver('[email protected]')
    
    @logger.main
      - addObserver(@logger.observers.email_devs)
      - addObserver(@logger.observers.email_support)
    

    The same is also true for metadata.

    @controller.homepage: Controller\Homepage
      = on: '/homepage'
    
    
    // also show homepage on root
    @controller.homepage
      = on: '/'
    
    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Apr 23, 2019)

  • v1.1.1(Jan 29, 2019)

  • v1.1.0(Apr 11, 2018)

    Features

    This release brings container meta data support. In plain PHP and for the container language.

    You are now able to assign meta data to a service as follows:

    @my.event_listener: App\EventListener\Thing
        = on: 'something', call: 'handleTheThing' 
    

    Fixes

    Methods stacking has been fixed. You can now stack multiple calls to the same method together.

    @my.registry: App\Registry
        - add('james')
        - add('John')
    
    Source code(tar.gz)
    Source code(zip)
Twittee is the smallest, and still useful, Dependency Injection Container in PHP

What is Twittee? Twittee is the smallest, and still useful, Dependency Injection Container in PHP; it is also probably one of the first public softwar

null 133 Dec 5, 2022
A small PHP dependency injection container

Pimple Caution! Pimple is now closed for changes. No new features will be added and no cosmetic changes will be accepted either. The only accepted cha

Silex 2.6k Dec 29, 2022
PSR-11 compatible Dependency Injection Container for PHP.

bitexpert/disco This package provides a PSR-11 compatible, annotation-based dependency injection container. Have a look at the disco-demos project to

bitExpert AG 137 Sep 29, 2022
The dependency injection container for humans

layout home PHP-DI is a dependency injection container meant to be practical, powerful, and framework-agnostic. Read more on the website: php-di.org G

null 2.4k Jan 4, 2023
Small but powerful dependency injection container

Container (Dependency Injection) This package is compliant with PSR-1, PSR-2, PSR-4 and PSR-11. If you notice compliance oversights, please send a pat

The League of Extraordinary Packages 779 Dec 30, 2022
Dependency Injection System

Aura.Di A serializable dependency injection container with constructor and setter injection, interface and trait awareness, configuration inheritance,

Aura for PHP 342 Dec 1, 2022
Yii Dependency Injection PSR-11 compatible

Yii Dependency Injection PSR-11 compatible dependency injection container that is able to instantiate and configure classes resolving dependencies. Fe

Yii Software 161 Nov 10, 2022
Dependency Manager for PHP

Composer - Dependency Management for PHP Composer helps you declare, manage, and install dependencies of PHP projects. See https://getcomposer.org/ fo

Composer 27.2k Dec 31, 2022
IoC Dependency Injector

auryn auryn is a recursive dependency injector. Use auryn to bootstrap and wire together S.O.L.I.D., object-oriented PHP applications. How It Works Am

Daniel Lowrey 725 Nov 23, 2022
IoC Dependency Injector

auryn auryn is a recursive dependency injector. Use auryn to bootstrap and wire together S.O.L.I.D., object-oriented PHP applications. How It Works Am

Daniel Lowrey 710 Apr 15, 2021