├── .gitignore
├── .travis.yml
├── README.md
├── composer.json
├── phpunit.xml.dist
├── src
├── Picotainer.php
└── PicotainerNotFoundException.php
└── tests
├── PicotainerTest.php
└── bootstrap.php
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | .project
3 | .settings
4 | composer.phar
5 | composer.lock
6 | .buildpath
7 |
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.1
5 | - 7.0
6 | - 5.6
7 | - 5.5
8 | - 5.4
9 | - hhvm
10 |
11 | install:
12 | - composer install --dev --no-interaction
13 |
14 | script:
15 | - mkdir -p build/logs
16 | - phpunit --coverage-clover build/logs/clover.xml
17 |
18 | after_script:
19 | - php vendor/bin/coveralls -v
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Picotainer
2 | ==========
3 | [](https://packagist.org/packages/mouf/picotainer)
4 | [](https://packagist.org/packages/mouf/picotainer)
5 | [](https://packagist.org/packages/mouf/picotainer)
6 | [](https://scrutinizer-ci.com/g/thecodingmachine/picotainer/?branch=1.0)
7 | [](https://insight.sensiolabs.com/projects/3ac43eac-dcec-496a-9e0f-5fe82f8b3824)
8 | [](https://travis-ci.org/thecodingmachine/picotainer)
9 | [](https://coveralls.io/r/thecodingmachine/picotainer?branch=1.0)
10 |
11 | This package contains a really minimalist dependency injection container (24 lines of code!) compatible with
12 | [container-interop](https://github.com/container-interop/container-interop) (supports ContainerInterface and
13 | delegate lookup feature). It is also, therefore, compatible with
14 | [PSR-11](https://github.com/php-fig/fig-standards/blob/master/proposed/container.md), the FIG container standard.
15 |
16 | Picotainer is heavily influenced by the [Pimple DI container](http://pimple.sensiolabs.org/). Think about it
17 | as a Pimple container with even less features, and ContainerInterop compatibility.
18 |
19 | Installation
20 | ------------
21 |
22 | Before using Picotainer in your project, add it to your `composer.json` file:
23 |
24 | ```
25 | $ ./composer.phar require mouf/picotainer ~1.0
26 | ```
27 |
28 |
29 | Storing entries in the container
30 | --------------------------------
31 |
32 | Creating a container is a matter of creating a `Picotainer` instance.
33 | The `Picotainer` class takes 2 parameters:
34 |
35 | - the list of entries, as an **array of anonymous functions**
36 | - an optional [delegate-lookup container](https://github.com/container-interop/container-interop/blob/master/docs/Delegate-lookup.md)
37 |
38 | ```php
39 | use Mouf\Picotainer\Picotainer;
40 | use Psr\Container\ContainerInterface;
41 |
42 | $container = new Picotainer([
43 | "myInstance"=>function(ContainerInterface $container) {
44 | return new MyInstance();
45 | },
46 | "myOtherInstance"=>function(ContainerInterface $container) {
47 | return new MyOtherInstance($container->get('myInstance'));
48 | }
49 | "myParameter"=>function(ContainerInterface $container) {
50 | return MY_CONSTANT;
51 | }
52 | ], $rootContainer);
53 | ```
54 |
55 | The list of entries is an associative array.
56 |
57 | - The key is the name of the entry in the container
58 | - The value is an **anonymous function** that will return the entry
59 |
60 | The entry can be anything (an object, a scalar value, a resource, etc...)
61 |
62 | The **anonymous function** must accept one parameter: the container on which dependencies will be fetched.
63 | The container is the "delegate-lookup container" if it was passed as the second argument of the constructor,
64 | or the Picotainer instance itself if no delegate lookup container was passed.
65 |
66 |
67 | Fetching entries from the container
68 | -----------------------------------
69 |
70 | Fetching entries from the container is as simple as calling the `get` method:
71 |
72 | ```php
73 | $myInstance = $container->get('myInstance');
74 | ```
75 |
76 | Why the need for this package?
77 | ------------------------------
78 |
79 | This package is part of a long-term effort to bring [interoperability between DI containers](https://github.com/container-interop/container-interop). The ultimate goal is to
80 | make sure that multiple containers can communicate together by sharing entries (one container might use an entry from another
81 | container, etc...)
82 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "mouf/picotainer",
3 | "description" : "This package contains a really minimalist dependency injection container compatible with container-interop.",
4 | "authors" : [{
5 | "name" : "David Négrier",
6 | "email" : "d.negrier@thecodingmachine.com",
7 | "homepage" : "http://mouf-php.com"
8 | }
9 | ],
10 | "keywords" : [
11 | "dependency injection",
12 | "DI",
13 | "container-interop"
14 | ],
15 | "homepage" : "http://mouf-php.com",
16 | "license" : "MIT",
17 | "require" : {
18 | "container-interop/container-interop" : "~1.2",
19 | "psr/container": "^1.0"
20 | },
21 | "require-dev" : {
22 | "phpunit/phpunit" : "~4.8",
23 | "satooshi/php-coveralls": "~1.0"
24 | },
25 | "autoload" : {
26 | "psr-4" : {
27 | "Mouf\\Picotainer\\" : "src/"
28 | }
29 | },
30 | "autoload-dev" : {
31 | "psr-4" : {
32 | "Mouf\\Picotainer\\" : "tests/"
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 | ./tests/
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Picotainer.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class Picotainer implements InteropContainer
14 | {
15 |
16 | /**
17 | * The delegate lookup.
18 | *
19 | * @var Psr11Container
20 | */
21 | protected $delegateLookupContainer;
22 |
23 | /**
24 | * The array of closures defining each entry of the container.
25 | *
26 | * @var array
27 | */
28 | protected $callbacks;
29 |
30 | /**
31 | * The array of entries once they have been instantiated.
32 | *
33 | * @var array
34 | */
35 | protected $objects;
36 |
37 | /**
38 | * Instantiate the container.
39 | *
40 | * @param array $entries Entries must be passed as an array of anonymous functions.
41 | * @param Psr11Container $delegateLookupContainer Optional delegate lookup container.
42 | */
43 | public function __construct(array $entries, Psr11Container $delegateLookupContainer = null)
44 | {
45 | $this->callbacks = $entries;
46 | $this->delegateLookupContainer = $delegateLookupContainer ?: $this;
47 | }
48 |
49 | /* (non-PHPdoc)
50 | * @see \Interop\Container\ContainerInterface::get()
51 | */
52 | public function get($identifier)
53 | {
54 | if (isset($this->objects[$identifier])) {
55 | return $this->objects[$identifier];
56 | }
57 | if (!isset($this->callbacks[$identifier])) {
58 | throw new PicotainerNotFoundException(sprintf('Identifier "%s" is not defined.', $identifier));
59 | }
60 |
61 | return $this->objects[$identifier] = $this->callbacks[$identifier]($this->delegateLookupContainer);
62 | }
63 |
64 | /* (non-PHPdoc)
65 | * @see \Interop\Container\ContainerInterface::has()
66 | */
67 | public function has($identifier)
68 | {
69 | return isset($this->callbacks[$identifier]) || isset($this->objects[$identifier]);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/PicotainerNotFoundException.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | class PicotainerNotFoundException extends \InvalidArgumentException implements NotFoundException
12 | {
13 | }
14 |
--------------------------------------------------------------------------------
/tests/PicotainerTest.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 | class PicotainerTest extends \PHPUnit_Framework_TestCase
10 | {
11 |
12 | public function testGet()
13 | {
14 | $container = new Picotainer([
15 | "instance" => function () { return "value"; },
16 | ]);
17 |
18 | $this->assertSame('value', $container->get('instance'));
19 | }
20 |
21 | /**
22 | *
23 | * @expectedException Mouf\Picotainer\PicotainerNotFoundException
24 | */
25 | public function testGetException()
26 | {
27 | $container = new Picotainer([]);
28 |
29 | $container->get('nonexistant');
30 | }
31 |
32 | public function testDelegateContainer()
33 | {
34 | $container = new Picotainer([
35 | "instance" => function () { return "value"; },
36 | ]);
37 |
38 | $container2 = new Picotainer([
39 | "instance2" => function ($container) { return $container->get('instance'); },
40 | ], $container);
41 |
42 | $this->assertSame('value', $container2->get('instance2'));
43 | }
44 |
45 | public function testOneInstanceOnly()
46 | {
47 | $container = new Picotainer([
48 | "instance" => function () { return new \stdClass(); },
49 | ]);
50 |
51 | $instance1 = $container->get('instance');
52 | $instance2 = $container->get('instance');
53 |
54 | $this->assertSame($instance1, $instance2);
55 | }
56 |
57 | public function testHas()
58 | {
59 | $container = new Picotainer([
60 | "instance" => function () { return "value"; },
61 | ]);
62 |
63 | $this->assertTrue($container->has('instance'));
64 | $this->assertFalse($container->has('instance2'));
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 |