├── .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 | [![Latest Stable Version](https://poser.pugx.org/mouf/picotainer/v/stable.svg)](https://packagist.org/packages/mouf/picotainer) 4 | [![Latest Unstable Version](https://poser.pugx.org/mouf/picotainer/v/unstable.svg)](https://packagist.org/packages/mouf/picotainer) 5 | [![License](https://poser.pugx.org/mouf/picotainer/license.svg)](https://packagist.org/packages/mouf/picotainer) 6 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/thecodingmachine/picotainer/badges/quality-score.png?b=1.0)](https://scrutinizer-ci.com/g/thecodingmachine/picotainer/?branch=1.0) 7 | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/3ac43eac-dcec-496a-9e0f-5fe82f8b3824/mini.png)](https://insight.sensiolabs.com/projects/3ac43eac-dcec-496a-9e0f-5fe82f8b3824) 8 | [![Build Status](https://travis-ci.org/thecodingmachine/picotainer.svg?branch=1.0)](https://travis-ci.org/thecodingmachine/picotainer) 9 | [![Coverage Status](https://coveralls.io/repos/thecodingmachine/picotainer/badge.svg?branch=1.0)](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 |