gravatalonga / container
Implementation of PSR-11 Container, it is lightweight yet powerful. Feature such as Lazy Factory, Factory, Optinal Share of Services, Array Access and other it can be very versatile.
Fund package maintenance!
gravataLonga
Installs: 2 032
Dependents: 1
Suggesters: 0
Security: 0
Stars: 4
Watchers: 1
Forks: 1
Open Issues: 0
Requires
- php: ^8.0|^8.1
- psr/container: ^2.0
Requires (Dev)
- infection/infection: ^0.18.0
- phpunit/phpunit: ^9
- rector/rector: ^0.13.4
- scrutinizer/ocular: ^1.9
- vimeo/psalm: ^4.3.0
Provides
README
Container
Container implementation which follow PSR-11.
Requirements
Installation
composer require gravatalonga/container
Usage
Basic Usage
use Gravatalonga\Container\Container; $container = new Container(); $container->set('random', function() { return rand(0, 1000); }); $container->share('uniqueSeed', function() { return rand(0, 1000); }); // create alias 'sessionId' $container->alias('uniqueSeed', 'sessionId'); echo $container->get('random'); // get random number each time you call this. if ($container->has('uniqueSeed')) { echo $container->get('uniqueSeed'); // get same random number. }
When creating a new instance of Container, you can pass on first argument configurations or entries to be already bonded into container.
use Gravatalonga\Container\Container; new Container([ 'settings' => ['my-settings'], FooBar::class => function (\Psr\Container\ContainerInterface $c) { return new FooBar(); } ]);
Using Service Provider
use Gravatalonga\Container\Container; $container = new Container(); $container->set(RedisClass::class, function () { return new RedisClass(); }); // then you can use... $cache = $container->get('Cache');
When using set
, factory
or share
with Closure and if you want to get Container
it's self, you can pass type hint of ContainerInterface
as argument.
use Gravatalonga\Container\Container; use Psr\Container\ContainerInterface; $container = new Container([ 'server' => 'localhost', 'username' => 'root' ]); $container->set('Cache', function (ContainerInterface $container) { // some where you have binding this RedisClass into container... return $container->make(RedisClass::class, [ 'server' => $container->get('server'), 'username' => $container->get('username') ]); }); // set is a method alias of factory $container->factory('CacheManager', function() { return new CacheManager(); }); // then you can use... $cache = $container->get('Cache');
Using Array like access
use Gravatalonga\Container\Container; $container = new Container(); $container[FooBar::class] = function(ContainerInterface $container) { return new FooBar($container->get('settings')); }; if (isset($container[FooBar::class])) { echo $container[FooBar::class]->helloWorld(); }
Alias
Alias like the name show, it to make a possibility to make an alias from one entry to another. It will throw an exception if can't be found.
use Gravatalonga\Container\Container; $container = new Container(); $container->set('settings', ['driver' => 'default']); $container->set(FooBar::class, function($settings) { return new FooBar($settings); }); $container->alias(FooBar::class, 'foo.bar'); $foobar = $container->get('foo.bar');
Callable as alternative
use Gravatalonga\Container\Container; $class = new class { public function get(): int { return mt_rand(0, 100); } }; $container = new Container(); $container->factory('random', [$class, 'get']); $foobar = $container->get('random'); // it will get random int
Extend
In order implementation to be ease for other services providers extend
method was created.
use Gravatalonga\Container\Container; class Test { /** * @var string */ public $name; public function __construct($name = 'Jonathan Fontes') { $this->name = $name; } } $container = new Container(); $container->get(Test::class, function(ContainerInterface $container) { return new Test; }); $container->extend(Test::class, function(ContainerInterface $container, $test) { return new Test($test->name.' - The greatest!'); }); echo $container->get(Test::class); // It will print 'Jonathan Fontes - The greatest!';
Advance usage
Container is capable to resolve class who isn't bounded, it will resolve dependencies from __construct
type-hint/built-in which is bounded. Read example code below:
Information: built-in is type which is built in on PHP, which is
string
,int
,boolean
, etc. Type Hint is type which is created by user land, such as, when creating a class you are creating a new type.
Using Type Hint Class
use Gravatalonga\Container\Container; class FooBar {} class Test { public function __construct(FooBar $foobar) { $this->foobar = $foobar; } } $container = new Container(); $container->set(FooBar::class, function () { return new FooBar(); }); $container->get(Test::class); // FooBar it will inject into Test class.
Note: We only support resolving auto wiring argument on construction if they are bounded into container. Otherwise it will throw an exception if can't find entry.
Using Built in type
use Gravatalonga\Container\Container; class Test { public function __construct(string $name) { $this->name = $name; } } $container = new Container(); $container->set('name', 'my-var'); $container->get(Test::class); // my-var it will inject into Test class.
If argument accept nullable if can't be resolve it will pass default value which in this case is null
.
use Gravatalonga\Container\Container; class Test { /** * @var string */ private $name; public function __construct(string $name = null) { $this->name = $name; } } $container = new Container(); $container->get(Test::class); // null it will inject into Test class.
In also attempt to resolve auto wiring of construction by its default value, it will check default value of __construct
and it will pass that default value.
First case, if value is a simple built-in type value.
use Gravatalonga\Container\Container; class Test { /** * @var string */ private $name; public function __construct($name = 'Jonathan Fontes') { $this->name = $name; } } $container = new Container(); $container->get(Test::class); // 'Jonathan Fontes' it will pass into container...
Tip
It's well-known that using singleton pattern, it's an anti-pattern. But small feature can't hurt you
So, you can use:
$container = new Container();
// ...
Container::setInstance($container);
Then you can get instance of container,
$container = Container::getInstance();
Tips: The container can detected circular dependencies.
Change log
Please see CHANGELOG for more information on what has changed recently.
Testing
composer grumphp
Contributing
Please see CONTRIBUTING and CODE_OF_CONDUCT for details.
Security
If you discover any security related issues, please email jonathan.alexey16[at]gmail.com instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.