calgamolib / di
Pimple-like DI container library.
Requires
- php: >=7.1
- ext-json: *
- calgamolib/annotations: ~0.1
- calgamolib/cache: ~0.1
- psr/container: ^1.0
Requires (Dev)
- mikey179/vfsstream: 1.3.*
- php-coveralls/php-coveralls: ^2.0
- phpunit/phpunit: ^6.3.0
This package is auto-updated.
Last update: 2019-12-09 09:17:11 UTC
README
Description
Calgamo/Di is a Pimple style dependency injection(DI) container library.
Feature
- Pimple style API
- Lazy creation for better performance
- Multi container builders
- Protecting or restricting component
- Cacheable
- Dynamic code generation for bootstrap
- Dependency injection:
- autowired
- constructor,setter,field injection
- scope: singleton/prototype
- custom annotation:
- @Inject
- @Scope
- @Singleton
- @Named
- @Prototype
Requirement
PHP 7.1 or later
Installing calgamo/di
The recommended way to install calgamo/di is through Composer.
composer require calgamo/di
After installing, you need to require Composer's autoloader:
require 'vendor/autoload.php';
Usage
1.Building Container
Container will be created by builder class or directly created. You can choose the way of creation container as you like.
There are several method of container building:
- Simple(no container builder)
- Bootstrap Container Builder
- Compiler Container Builder
- Modular Container Builder
- Cached Compiler Container Builder
Simple(no container builder)
You can build container without any built-in container builder.
This method is simple and fastest, but container initializing code will be complex if you use many components.
use Calgamo\Di\Container; use Sample\Person; $container = Container(); $container['david'] = function(Container $c){ return new Person('David Smith', 24, 179.2, function($target){ return 'throws '.$target.'.'; }); }; $david = $container['david']; $david->sayHello(); // David Smith says "Hello! My name is David Smith. I am 24 years old."
Bootstrap Container Builder
Botstrap container builder will setup a container by code written in callback function(bootstrap). This method is very fast, but may be redundant.
use Calgamo\Di\Container; use Calgamo\Di\BootstrapContainerBuilder; use Sample\Person; $bootstrap = function(Container $c){ $c['david'] = function(Container $c){ return new Person('David Smith', 24, 179.2, function($target){ return 'throws '.$target.'.'; }); }; }; $bulder = new BootstrapContainerBuilder($bootstrap); $container = $bulder->build(); $david = $container['david']; $david->sayHello(); // David Smith says "Hello! My name is David Smith. I am 24 years old."
Compiler Container Builder
Compiler container builder will setup a container by configuration file(supports .json/.yml/.php). This container builder generates bootstrap code dynamically in cache directory, so container activation time will be greatly reduced after the second time.
sample.php
use Calgamo\Di\CompilerContainerBuilder; use Calgamo\Config\Util\ConfigFileUtil; $config = ConfigFileUtil::loadConfigFromFile('components.json'); $container = (new CompilerContainerBuilder($config))->build(); $david = $container['david']; $david->sayHello(); // David Smith says "Hello! My name is David Smith. I am 24 years old."
components.json
{ "compiler": { "vendor_dir": "../vendor", "autoloaders": [ "../sample_autoloader2.php" ] }, "cache": { "root": "../cache", "filename": "demo_di" }, "components": [ { "id": "david", "type": "object", "class_name": "Sample\\Person", "injections": [ { "new": [ "David Smith", "@int: 24", "@float: 179.2", "@func: function($target){ return 'throws '.$target.'.'; }" ] } ] } ] }
@ directive
As above config file(components.json), you an use '@xxx' direcive in component config file.
There are '@xxx' direcives below.
Directive | Replaced | Sample |
---|---|---|
@id: [component_id] | other component identified by [component_id] | @id: logger |
@func: [function_code] | [function_code] | @func: function($a) { echo $s; } |
@int: [integer_value] | [integer_value] | @int: 100 |
@float: [float_value] | [float_value] | @float: 3.14 |
@bool: [bool_value] | [bool_value]('yes' or '1' or 'on' regarded as true) | @bool: yes @bool: true |
@json: [json_data] | decoded json | @json: { 'age': '21', 'name': 'david' } |
@env: [key] | $_ENV value($_ENV['key']) | @env: USER |
Modular Container Builder
Modular container builder will setup a container by installing "container module".
Container module is a set of container initializing code.
BootstrapContainerBuilder provide only one set of initializing code, but ModularContainerBuilder accepts
multiple modules if you need.
use Calgamo\Di\Container; use Calgamo\Di\ModularContainerBuilder; use Calgamo\Di\ContainerModuleInterface; use Sample\Person; class DavidModule implements ContainerModuleInterface { public function install(Container $container) { $container['david'] = function(){ return new Person('David Smith', 24, 179.2, function($target){ return 'throws '.$target.'.'; }); }; } } $builder = new ModularContainerBuilder([ new DavidModule() ]); $container = $builder->build(); $david = $container['david']; $david->sayHello(); // David Smith says "Hello! My name is David Smith. I am 24 years old."
2.Using Container
get
// get service $service = $container['my-service']; // do something $service->doSomething();
set/unset
You can set instance or value to container in the same way. Also you can set factory code for generate instance or constant value for lazy creation.
// set object $container['my-favorite-fruits'] = new MyService(); // set object factory(lazy creation) $container['my-service'] = function(){ return new MyService(); }; // set constant value $container['my-favorite-fruits'] = [ 'apple', 'banana' ]; // set constant value factory(lazy creation) $container['my-service'] = function(){ return [ 'apple', 'banana' ]; }; // unset entry unset($container['my-favorite-fruits']);
slot
Slot is information about container component. You can lock or restrict component via slot object.
// get slot object $slot = $contianer->slot('something'); // lock the slot(in this case, 'something' slot will be locked) $slot->lock(); // type restriction $slot->mustBeTypeOf('array'); // instance-of restriction $slot->mustBeInstanceOf('MyServiceInterface');
Tips
getting new instance for each access
By default, container returns existing object after second access. But you can retrieve new object for each access by calling Container#newInstance() method.
$cart = $container['cart']; echo 'count:' . $cart->countItems(); // count: 0 $cart->addItem('apple'); echo 'count:' . $cart->countItems(); // count: 1 $cart = $container['cart']; echo 'count:' . $cart->countItems(); // count: 1 $cart = $container->newInstance('cart'); echo 'count:' . $cart->countItems(); // count: 0
Protect component
You can protect component for using Slot#lock() method.
$container['cart'] = new MyCart(); // lock slot $container->slot('cart')->lock(); // this will fail becasue the slot is locked $container['cart'] = new AnotherCart(); // throws SlotIsLockedException
Restrict component type
You can restrict component type for using Slot#mustBeTypeOf() method.
$container['something'] = new MyCart(); // restrict slot to array value $container->slot('something')->mustBeTypeOf('array'); // this will fail because AnotherCart is not array $container['something'] = new AnotherCart(); // throws SlotTypeRestrictionViolationException // array value can be set $container['something'] = [ 'apple', 'banana' ];
Restrict component class or interface
You can restrict component class or interface for using Slot#mustBeInstanceOf() method.
$container['something'] = new MyCart(); // restrict slot to array value $container->slot('something')->mustBeInstanceOf('MyServiceInterface'); // this will fail because AnotherCart does not implement MyServiceInterface $container['something'] = new AnotherCart(); // throws SlotInstanceOfRestrictionViolationException // interface implemented instance can be set in this slot $container['something'] = new MyService; // class MyService implements MyServiceInterface
Extending component
You can extend component by using Container#extend() method.
// register my service $container['my_service'] = new MyService(); // extend my serice(set max item count) $container->extend('my_service', function($my_service) { $my_service->setMaxItems(10); }); echo 'max: ' . $container['my_service']->getMaxItems(); // max: 10 // register array $container['my_favorite_fruits'] = ['apple']; // add banana to my favorites array $container->extend('my_favorite_fruits', function(&$favorites) { $favorites[] = 'banana'; }); echo implode(', ',$container['my_favorite_fruits']); // apple, banana
Compiler config file format & parameters
Compiler config file can be written in json, YAML, and PHP format. All parameters mest begin with array element.
Component config file: json format sample
{ "compiler": { "vendor_dir": "../vendor", "autoloaders": [ "../sample_autoloader2.php" ] }, "cache": { "root": "../cache", "filename": "demo_di" }, "slots": [ { "id": "david", "type": "object", "instanceOf": "\\Sample\\PersonInterface", "locked": true } ], "components": [ { "id": "david", "type": "object", "class_name": "Sample\\Person", "injections": [ { "new": [ "David Smith", "@int: 24", "@float: 179.2", "@func: function($target){ return 'throws '.$target.'.'; }" ] } ] } ] }
Component config file: YAML format sample
compiler: vendor_dir: "../vendor" autoloaders: "../sample_autoloader2.php" cache: root: "../cache", filename: demo_di slots: - id: david, type: object, instanceOf: \Sample\PersonInterface, locked: true components: - id: david, type: object, class_name: Sample\Person, injections": new: - "David Smith" - "@int: 24" - "@float: 179.2" - "@func: function($target){ return 'throws '.$target.'.'; }"
Component config file: PHP format sample
<?php return [ 'compiler' => [ 'vendor_dir' => '../vendor', 'autoloaders' => [ '../sample_autoloader2.php' ], ], 'cache' => [ 'root' => '../cache', 'filename' => 'demo_di', ], 'slots' => [ [ 'id' => 'david', 'type' => 'object', 'instanceOf' => '\Sample\PersonInterface', 'locked' => true, ] ], 'components' => [ [ 'id' => 'david', 'type' => 'object', 'class_name' => 'Sample\Person', 'injections' => [ 'new' => [ "David Smith", "@int: 24", "@float: 179.2", "@func: function(\$target){ return 'throws '.\$target.'.'; }", ] ] ] ], ];
Component config file: parameters
Parameter | Mandatory | Explain | Sample |
---|---|---|---|
compiler/vendor_dir | Yes | Indicates composer vendor directory path | vendor_dir: "../vendor" |
compiler/autoloaders | No | Indicates user defined autoloaders file. In the file, use spl_autoload_register globally to register your own autoloader. | autoloaders: "../my_autoloader.php" |
cache/root | No | Indicates cache directory. Compiler will output bootstrap PHP code in this directory. | root: "../cache" |
cache/filename | No | Indicates file basename of bootstrap cache code. The fulle name of cache file will be generated by adding postfix '.php' | filename: "my_bootstrap" |
slots | No | Indicates slot array, which is attached to container component to restrict it. See slot item parameters | - |
components | Yes | Indicates component array. See component item parameters | - |
Component config file: slot item parameters
Parameter | Explain | Sample |
---|---|---|
id | Indicates slot id | id: "my_service" |
type | Indicates type of slot | type: object |
instanceOf | Indicates class or intarface which component implements or inherit | instanceOf: MyServiceInterface |
locked | Indicates slot is locked. If slot is locked, you can not overwrite it. | locked: true |
Component config file: component item parameters
Parameter | Explain | Sample |
---|---|---|
id | Indicates component id | id: "my_service" |
type | Indicates type of component | type: object |
class | Indicates class of component | instanceOf: MyService |
injections | Indicates array of injections. See [component injections parameter](#component_injections) | locked: true |
Component config file: component injections parameter
Parameter | Value Type | Explain | Sample |
---|---|---|---|
new | array | Indicates constructor injection. Value will be passed to constructor | new: [ "param1", "param2" ] |
method | string | Indicates method injection. Value means method name. | method: doSomething |
property | string | Indicates property injection. Value means property name. The property must be public. | property: tax_ratio |
params | array | Indicates parameters of method injection. Value must be array. | params: [ "pram1", "param2" ] |
value | int string bool float null array |
Indicates value of property injection. | value: "tomato" |
License
This library is licensed under the MIT license.
Author
Disclaimer
This software is no warranty.
We are not responsible for any results caused by the use of this software. Please use the responsibility of the your self.