Skip to content

asispts/dicontainer

Repository files navigation

DiContainer

Build Coverage Status License PHP Version Stable unstable

PSR-11 compliant PHP dependency injection container.

Table of Contents

Installation

Use composer to install the library.

composer require xynha/dicontainer

Usage

DiContainer can be used with or without configuration. All classes that do not required constructor arguments, can be created directly.

// Without configuration
$dic = new DiContainer(new DiRuleList);

$obj = $this->dic->get('classname');

However, for complex initialization, you have to define DiContainer rules and pass them to DiRuleList.

// Construct rule list
$rlist = new DiRuleList();

// Add configuration from file
$json = json_decode(file_get_contents('filename'), true);
$rlist = $rlist->addRules($json);

// Add configuration manually
$rule['shared'] = true;
$rlist = $rlist->addRule('classname', $rule);

// Construct the container
$dic = new DiContainer($rlist);

$obj = $this->dic->get('classname');

DiContainer rules

General format of DiContainer rules in JSON format:

{
  "rule_key" : {
    "config_keys": "config_value"
  },
  "another_rule_key" : {
    "config_keys": "config_value"
  }
}

Where:

  • rule_key, another_rule_key are a class or an interface namespace, and
  • config_keys are supported rule keys:
    • shared
    • instanceOf
    • constructParams
    • substitutions
    • getFrom

# shared: boolean (default false)

  • Possible values:
    • true, if the constructed instance can be shared betwen classes during execution,
    • false, otherwise.
  • Example:
    "classA" : {
      "shared" : true
    },
    "classB" : {
      "shared" : false
    }

# instanceOf: string|object (default null)

  • To override class or interface defined in rule_key.
  • Possible values:
    • string: class namespace
    • object: already constructed instance.
  • Example:
    "interfaceA" : {
      "instanceOf" : "classA"
    }
    Example of passing already constructed instance,
    $rlist = new DiRuleList();
    $rule['interfaceA'] = ['instanceOf' => $object];
    $rlist = $rlist->addRules($rule);

# constructParams: array (default null)

  • constructParams is a list of constructor argument values.
  • Example:
    "classA" : {
      "constructParams" : [
        "arg1",
        "arg2"
      ]
    }
  • Construct params can also be retrieved from another class by using CALL::OBJECT and CALL::SCALAR identifiers.
  • CALL::SCALAR is used to retrieve array and scalar values
  • CALL::OBJECT is used to retrieve object value.
  • CALL::OBJECT and CALL::SCALAR format:
"constructParams": [
  ["CALL::SCALAR", ["callback"], ["array_of_callback_arguments"]],
  ["CALL::OBJECT", ["callback"], ["array_of_callback_arguments"]]
]
  • Example:
class Config{
  public function getConfig(string $key){
    if ($key === 'db'){
      return 'dbconfig';
    }
  }
}

class DatabaseDriver{
  public function __construct(string $config){}
}

# if constructed manually,

$config = new Config();
$driver = new DatabaseDriver($config->getConfig('db'));

# using DiContainer

{
  "DatabaseDriver" : {
    "constructParams" : [
      ["CALL::SCALAR", ["Config","getConfig"], ["db"]]
    ]
  }
}
$driver = $dic->get(DatabaseDriver::class);
  • A constant can be passed to constructor arguments by using CALL::CONSTANT, for example
{
  "$pdo": {
    "instanceOf": "DatabaseDriver",
    "constructParams": [
      [
        ["CALL::CONSTANT", "PDO::ATTR_ERRMODE"],
        ["CALL::CONSTANT", "PDO::ERRMODE_EXCEPTION"]
      ]
    ]
  }
}

# substitutions: associative array (default null)

  • Substitute interface in the constructor argument with a substituted class.
  • Example
    "classA" : {
      "substitutions" : {
        "interfaceB" : "classB",
        "interfaceC" : "classC",
      }
    }

# getFrom: array (default null)

  • Get rule_key instance from a factory or a class.
  • getFrom format
    "getFrom" : [
      ["callback"],
      [ "array_of_callback_arguments" ]
    ]
  • Example
    "classA" : {
      "getFrom" : [
        ["FactoryClassA", "getClassA"],
        ["arg1","arg2"]
      ]
    },
    "interfaceB" : {
      "getFrom" : [
        ["FactoryClassB", "getClassB"],
        ["arg1",["array", "arguments"]]
      ]
    }

Use cases

Please check unit test configuration files in tests/Data/config and the corresponding tests.

Changelog

See CHANGELOG.md

Contributing

All form of contributions are welcome. You can report issues, fork the repo and submit pull request.

For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

Released under Apache-2.0 License. See LICENSE file for more details.

   Copyright 2020 Asis Pattisahusiwa

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.