Skip to content

Commit

Permalink
Merge upstream changes (#6)
Browse files Browse the repository at this point in the history
* Support nullable class type hints (Level-2#182)

* Remove PHP 8 deprecation warning

* Level-2#195 - stop some parameters getting counted twice

* Fix issue where 'shareInstances' resolve but fail to propagate (Level-2#201)

* Level-2#200 - Expand shareInstances test to replicate propagation issue

* Level-2#200 - Fix issue where 'shareInstances' resolve but fail to propagate

Because `$share` is passed by reference to `matchParam()`, and
`matchParam()` removes matching objects from its `$search` array,
instances may be removed from `$share` before it is passed to `expand()`
or `create()`. Depending on the order of constructor parameters and the
relative placement of `shareInstances` dependencies in the object tree,
this may result in multiple instances of these dependencies being
created.

Fixed by passing a copy of the `$share` array to `matchParam()`.

- Updated CI to use github actions

Co-authored-by: thisispiers <[email protected]>
Co-authored-by: Tom Butler <[email protected]>
Co-authored-by: Luke Arms <[email protected]>
  • Loading branch information
4 people authored Oct 3, 2022
1 parent 0abde11 commit 9b54e76
Show file tree
Hide file tree
Showing 20 changed files with 165 additions and 49 deletions.
3 changes: 0 additions & 3 deletions .coveralls.yml

This file was deleted.

41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Dice CI

on:
push:
branches:
- main
pull_request:

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
php: [ '7.1', '7.4', '8.0', '8.1' ]

steps:
- name: Setup PHP with PECL extension
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
ini-file: development
tools: composer
- uses: actions/checkout@v2
- name: Install PHP Dependancies
run: composer install
- name: Run tests with coverage
env:
XDEBUG_MODE: coverage
run: composer test-coverage
- name: Upload coverage results to Coveralls
uses: nick-invision/retry@v2
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_PARALLEL: true
COVERALLS_FLAG_NAME: "PHP${{ matrix.php }}"
with:
timeout_seconds: 60
max_attempts: 3
command: php vendor/bin/php-coveralls -x clover.xml -o coveralls-upload.json -v
34 changes: 18 additions & 16 deletions src/Dice.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* @copyright 2012-2020 Tom Butler <[email protected]> | https://r.je/dice
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/

namespace Dice;
class Dice
{
Expand Down Expand Up @@ -112,12 +113,10 @@ public function getRule(string $name): array
/**
* Returns a fully constructed object based on $name using $args and $share as constructor arguments if supplied
* @template T
* @param string $name The name of the class to instantiate
* @psalm-param class-string<T> $name
* @param array $args An array with any additional arguments to be passed into the constructor upon instantiation
* @param array $share a list of defined in shareInstances for objects higher up the object graph, should only be used internally
* @return object A fully constructed object based on the specified input arguments
* @psalm-return T
*/
Expand Down Expand Up @@ -204,7 +203,7 @@ private function getClosure(string $name, array $rule)
//Internal classes may not be able to be constructed without calling the constructor and will not suffer from #7, construct them normally.
if ($class->isInternal()) {
$this->instances[$name] = $this->instances[
"\\" . $name
"\\" . $class->name
] = $closure($args, $share);
} else {
//Otherwise, create the class without calling the constructor (and write to \$name and $name, see issue #68)
Expand Down Expand Up @@ -331,11 +330,11 @@ private function expand(
? $this->create($param)
: $param;
}
/**
* Looks through the array $search for any object which can be used to fulfil $param
The original array $search is modifed so must be passed by reference.

*/
/**
* Looks through the array $search for any object which can be used to fulfil $param
* The original array $search is modifed so must be passed by reference.
*/
private function matchParam(
\ReflectionParameter $param,
$class,
Expand All @@ -353,6 +352,7 @@ private function matchParam(
}
return false;
}

/**
* Returns a closure that generates arguments for $method based on $rule and any $args passed into the closure
* @param object $method An instance of ReflectionMethod (see: {@link http:// php.net/manual/en/class.reflectionmethod.php})
Expand All @@ -366,9 +366,7 @@ private function getParams(\ReflectionMethod $method, array $rule)
foreach ($method->getParameters() as $param) {
$pType = $param->getType();
$class =
$pType &&
!$pType->isBuiltin() &&
$pType instanceof \ReflectionNamedType
$pType instanceof \ReflectionNamedType && !$pType->isBuiltin()
? $pType->getName()
: null;
$paramInfo[] = [
Expand Down Expand Up @@ -407,22 +405,26 @@ private function getParams(\ReflectionMethod $method, array $rule)
}
// Do the same with $share
elseif (
$share &&
($match = $this->matchParam($param, $class, $share)) !==
($copy = $share) &&
($match = $this->matchParam($param, $class, $copy)) !==
false
) {
$parameters[] = $match;
}
// When nothing from $args or $share matches but a class is type hinted, create an instance to use, using a substitution if set
elseif ($class) {
try {
$parameters[] = $sub
? $this->expand(
if ($sub) {
$parameters[] = $this->expand(
$rule["substitutions"][$class],
$share,
true
)
: $this->create($class, [], $share);
);
} else {
$parameters[] = !$param->allowsNull()
? $this->create($class, [], $share)
: null;
}
} catch (\InvalidArgumentException $e) {
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/BasicTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public function testPassGlobals()
$_GET["foo"] = "bar";

$dice = $this->dice->addRule("CheckConstructorArgs", [
"constructParams" => [[\Dice\Dice::GLOBAL => "_GET"]],
"constructParams" => [[Dice\Dice::GLOBAL => "_GET"]],
]);

$obj = $dice->create("CheckConstructorArgs");
Expand Down Expand Up @@ -218,7 +218,7 @@ public function testImmutability()
public function testPassSelf()
{
$dice = $this->dice->addRule("CheckConstructorArgs", [
"constructParams" => [[\Dice\Dice::INSTANCE => \Dice\Dice::SELF]],
"constructParams" => [[Dice\Dice::INSTANCE => Dice\Dice::SELF]],
]);

$obj = $dice->create("CheckConstructorArgs");
Expand Down
5 changes: 3 additions & 2 deletions tests/CallTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/* @description Dice - A minimal Dependency Injection Container for PHP *
* @author Tom Butler [email protected] *
* @copyright 2012-2018 Tom Butler <[email protected]> | https:// r.je/dice.html *
Expand Down Expand Up @@ -71,8 +72,8 @@ public function testCallChain()
$rules = [
"TestCallImmutable" => [
"call" => [
["call1", ["foo"], \Dice\Dice::CHAIN_CALL],
["call2", ["bar"], \Dice\Dice::CHAIN_CALL],
["call1", ["foo"], Dice\Dice::CHAIN_CALL],
["call2", ["bar"], Dice\Dice::CHAIN_CALL],
],
],
];
Expand Down
11 changes: 6 additions & 5 deletions tests/ChainTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/* @description Dice - A minimal Dependency Injection Container for PHP *
* @author Tom Butler [email protected] *
* @copyright 2012-2018 Tom Butler <[email protected]> | https:// r.je/dice.html *
Expand Down Expand Up @@ -26,8 +27,8 @@ public function testMultipleChainCall()
'$someClass' => [
"instanceOf" => "Factory",
"call" => [
["get", [], \Dice\Dice::CHAIN_CALL],
["getBar", [], \Dice\Dice::CHAIN_CALL],
["get", [], Dice\Dice::CHAIN_CALL],
["getBar", [], Dice\Dice::CHAIN_CALL],
],
],
]);
Expand All @@ -43,7 +44,7 @@ public function testChainCallShared()
'$someClass' => [
"shared" => true,
"instanceOf" => "Factory",
"call" => [["get", [], \Dice\Dice::CHAIN_CALL]],
"call" => [["get", [], Dice\Dice::CHAIN_CALL]],
],
]);

Expand All @@ -57,7 +58,7 @@ public function testChainCallInject()
$dice = $this->dice->addRules([
"FactoryDependency" => [
"instanceOf" => "Factory",
"call" => [["get", [], \Dice\Dice::CHAIN_CALL]],
"call" => [["get", [], Dice\Dice::CHAIN_CALL]],
],
]);

Expand All @@ -72,7 +73,7 @@ public function testChainCallInjectShared()
"FactoryDependency" => [
"shared" => true,
"instanceOf" => "Factory",
"call" => [["get", [], \Dice\Dice::CHAIN_CALL]],
"call" => [["get", [], Dice\Dice::CHAIN_CALL]],
],
]);

Expand Down
10 changes: 9 additions & 1 deletion tests/ConstructParamsTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/* @description Dice - A minimal Dependency Injection Container for PHP *
* @author Tom Butler [email protected] *
* @copyright 2012-2018 Tom Butler <[email protected]> | https:// r.je/dice.html *
Expand Down Expand Up @@ -57,7 +58,7 @@ public function testInternalClassExtendedConstructor()
public function testDefaultNullAssigned()
{
$rule = [];
$rule["constructParams"] = [[\Dice\Dice::INSTANCE => "A"], null];
$rule["constructParams"] = [[Dice\Dice::INSTANCE => "A"], null];
$dice = $this->dice->addRule("MethodWithDefaultNull", $rule);
$obj = $dice->create("MethodWithDefaultNull");
$this->assertNull($obj->b);
Expand Down Expand Up @@ -138,4 +139,11 @@ public function testNullScalarNested()
$obj = $dice->create("NullScalarNested");
$this->assertEquals(null, $obj->nullScalar->string);
}

public function testNullableClassTypeHint()
{
$nullableClassTypeHint = $this->dice->create("NullableClassTypeHint");

$this->assertEquals(null, $nullableClassTypeHint->obj);
}
}
10 changes: 7 additions & 3 deletions tests/CreateArgsTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/* @description Dice - A minimal Dependency Injection Container for PHP *
* @author Tom Butler [email protected] *
* @copyright 2012-2018 Tom Butler <[email protected]> | https:// r.je/dice.html *
Expand Down Expand Up @@ -85,15 +86,18 @@ public function testTwoDefaultNullClass()
{
$obj = $this->dice->create("MethodWithTwoDefaultNullC");
$this->assertNull($obj->a);
$this->assertInstanceOf("NB", $obj->b);
$this->assertNull($obj->b);
// $this->assertInstanceOf("NB", $obj->b);
}

public function testTwoDefaultNullClassClass()
{
$obj = $this->dice->create("MethodWithTwoDefaultNullCC");
$this->assertNull($obj->a);
$this->assertInstanceOf("NB", $obj->b);
$this->assertInstanceOf("NC", $obj->c);
$this->assertNull($obj->b);
$this->assertNull($obj->c);
// $this->assertInstanceOf("NB", $obj->b);
// $this->assertInstanceOf("NC", $obj->c);
}

public function testScalarConstructorArgs()
Expand Down
3 changes: 2 additions & 1 deletion tests/DiceTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/* @description Dice - A minimal Dependency Injection Container for PHP *
* @author Tom Butler [email protected] *
* @copyright 2012-2018 Tom Butler <[email protected]> | https:// r.je/dice.html *
Expand Down Expand Up @@ -34,7 +35,7 @@ public function autoload($class)
protected function setUp(): void
{
parent::setUp();
$this->dice = new \Dice\Dice();
$this->dice = new Dice\Dice();
}

protected function tearDown(): void
Expand Down
15 changes: 8 additions & 7 deletions tests/NamedInstancesTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/* @description Dice - A minimal Dependency Injection Container for PHP *
* @author Tom Butler [email protected] *
* @copyright 2012-2018 Tom Butler <[email protected]> | https:// r.je/dice.html *
Expand All @@ -24,8 +25,8 @@ public function testMultipleSharedInstancesByNameMixed()

$rule = [];
$rule["constructParams"] = [
[\Dice\Dice::INSTANCE => "Y"],
[\Dice\Dice::INSTANCE => "[Y2]"],
[Dice\Dice::INSTANCE => "Y"],
[Dice\Dice::INSTANCE => "[Y2]"],
];

$dice = $dice->addRule("Z", $rule);
Expand All @@ -42,7 +43,7 @@ public function testNonSharedComponentByNameA()
$dice = $this->dice->addRule('$B', $rule);

$rule = [];
$rule["constructParams"][] = [\Dice\Dice::INSTANCE => '$B'];
$rule["constructParams"][] = [Dice\Dice::INSTANCE => '$B'];
$dice = $dice->addRule("A", $rule);

$a = $dice->create("A");
Expand All @@ -63,7 +64,7 @@ public function testNonSharedComponentByName()

$rule = [];

$rule["constructParams"][] = [\Dice\Dice::INSTANCE => '$Y2'];
$rule["constructParams"][] = [Dice\Dice::INSTANCE => '$Y2'];
$dice = $dice->addRule("Y1", $rule);

$y1 = $dice->create("Y1");
Expand All @@ -77,7 +78,7 @@ public function testSubstitutionByName()
$dice = $this->dice->addRule('$B', $rule);

$rule = [];
$rule["substitutions"]["B"] = [\Dice\Dice::INSTANCE => '$B'];
$rule["substitutions"]["B"] = [Dice\Dice::INSTANCE => '$B'];

$dice = $dice->addRule("A", $rule);
$a = $dice->create("A");
Expand All @@ -99,8 +100,8 @@ public function testMultipleSubstitutions()

$rule = [];
$rule["constructParams"] = [
[\Dice\Dice::INSTANCE => '$Y2A'],
[\Dice\Dice::INSTANCE => '$Y2B'],
[Dice\Dice::INSTANCE => '$Y2A'],
[Dice\Dice::INSTANCE => '$Y2B'],
];
$dice = $dice->addRule("HasTwoSameDependencies", $rule);

Expand Down
8 changes: 5 additions & 3 deletions tests/NamespaceTest.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<?php

/* @description Dice - A minimal Dependency Injection Container for PHP *
* @author Tom Butler [email protected] *
* @copyright 2012-2018 Tom Butler <[email protected]> | https:// r.je/dice.html *
* @license http:// www.opensource.org/licenses/bsd-license.php BSD License *
*/

class NamespaceTest extends DiceTest
{
public function testNamespaceBasic()
Expand All @@ -22,7 +24,7 @@ public function testNamespaceWithSlashrule()
{
$rule = [];
$rule["substitutions"]["Foo\\A"] = [
\Dice\Dice::INSTANCE => "Foo\\ExtendedA",
Dice\Dice::INSTANCE => "Foo\\ExtendedA",
];
$dice = $this->dice->addRule("\\Foo\\B", $rule);

Expand All @@ -34,7 +36,7 @@ public function testNamespaceWithSlashruleInstance()
{
$rule = [];
$rule["substitutions"]["Foo\\A"] = [
\Dice\Dice::INSTANCE => "Foo\\ExtendedA",
Dice\Dice::INSTANCE => "Foo\\ExtendedA",
];
$dice = $this->dice->addRule("\\Foo\\B", $rule);

Expand Down Expand Up @@ -69,7 +71,7 @@ public function testNamespaceRuleSubstitution()
{
$rule = [];
$rule["substitutions"]["Foo\\A"] = [
\Dice\Dice::INSTANCE => "Foo\\ExtendedA",
Dice\Dice::INSTANCE => "Foo\\ExtendedA",
];
$dice = $this->dice->addRule("Foo\\B", $rule);

Expand Down
Loading

0 comments on commit 9b54e76

Please sign in to comment.