diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 5cef83a..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,64 +0,0 @@ -version: 2.1 -aliases: - - &attach_workspace - attach_workspace: - at: ~/workspace - - &run_composer - run: - name: Install Composer Packages - command: | - cd ~/workspace/repo - composer install --optimize-autoloader -jobs: - php_setup: - docker: - - image: "cimg/php:7.4" - steps: - - checkout: - path: ~/workspace/repo - - run: - name: Enable Xdebug exit - command: | - sudo pecl install xdebug-3.1.5 - # We explcitly don't cache dependencies. - # The cache validation & fetching seems to take longer than fetching from source. - - *run_composer - - persist_to_workspace: - root: ~/workspace - paths: - - repo - php_74_tests: - docker: - - image: "cimg/php:7.4" - steps: &php_unit_test_steps - - *attach_workspace - - run: - name: Versions - command: | - php --version - composer --version - - run: - name: Static Analysis - command: | - cd ~/workspace/repo - ./vendor/bin/psalm - - run: - name: PHPUnit Tests - command: | - cd ~/workspace/repo - ./vendor/bin/phpunit -c phpunit.xml.dist - php_80_tests: - docker: - - image: "cimg/php:8.0" - steps: *php_unit_test_steps -workflows: - version: 2 - commit: - jobs: - - php_setup - - php_74_tests: - requires: - - php_setup - - php_80_tests: - requires: - - php_setup diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ba5bb1a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + +concurrency: + # Concurrency is only limited on pull requests. head_ref is only defined on PR triggers so otherwise it will use the random run id and always build all pushes. + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + phpunit-tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-version: ["7.4", "8.0", "8.1", "8.2"] + steps: + - uses: actions/checkout@v3 + - name: Installing PHP ${{ matrix.php-version }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + - name: Composer Install + run: composer install -o + - name: PHPUnit + run: ./vendor/bin/phpunit -c ./phpunit.xml.dist + - name: Static Analysis + run: ./vendor/bin/psalm diff --git a/composer.json b/composer.json index 4267f94..dec84d0 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ ], "require": { "php": ">=7.4", - "psr/container": "^1.0" + "psr/container": "*" }, "require-dev": { "phpunit/phpunit": "~8.0", diff --git a/src/Callback.php b/src/Callback.php index 50b2ef8..e7656ff 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -7,10 +7,13 @@ namespace Garden\Container; +use Prophecy\Call\Call; + /** * A reference that uses a callback to resolve. */ -class Callback implements ReferenceInterface { +class Callback implements ReferenceInterface +{ /** * @var callable $callback */ @@ -21,14 +24,16 @@ class Callback implements ReferenceInterface { * * @param callable $callback The callback of the reference. */ - public function __construct(callable $callback) { + public function __construct(callable $callback) + { $this->callback = $callback; } /** * {@inheritdoc} */ - public function resolve(Container $container, $instance = null) { + public function resolve(Container $container, mixed $instance = null) + { return call_user_func($this->callback, $container, $instance); } @@ -37,7 +42,8 @@ public function resolve(Container $container, $instance = null) { * * @return callable Returns the callback. */ - public function getCallback() { + public function getCallback(): callable + { return $this->callback; } @@ -47,7 +53,8 @@ public function getCallback() { * @param callable $callback The new callback to set. * @return Callback Returns `$this` for fluent calls. */ - public function setCallback($callback) { + public function setCallback(callable $callback): Callback + { $this->callback = $callback; return $this; } diff --git a/src/Container.php b/src/Container.php index 5600d7b..d7498e7 100644 --- a/src/Container.php +++ b/src/Container.php @@ -7,12 +7,14 @@ namespace Garden\Container; +use phpDocumentor\Reflection\Types\Boolean; use Psr\Container\ContainerInterface; /** * An inversion of control container. */ -class Container implements ContainerInterface, ContainerConfigurationInterface { +class Container implements ContainerInterface, ContainerConfigurationInterface +{ private $currentRule; private $currentRuleName; private $instances; @@ -22,18 +24,20 @@ class Container implements ContainerInterface, ContainerConfigurationInterface { /** * Construct a new instance of the {@link Container} class. */ - public function __construct() { - $this->rules = ['*' => ['inherit' => true, 'constructorArgs' => null]]; + public function __construct() + { + $this->rules = ["*" => ["inherit" => true, "constructorArgs" => null]]; $this->instances = []; $this->factories = []; - $this->rule('*'); + $this->rule("*"); } /** * Deep clone rules. */ - public function __clone() { + public function __clone() + { $this->rules = $this->arrayClone($this->rules); $this->rule($this->currentRuleName); } @@ -42,7 +46,8 @@ public function __clone() { * Clear all instances * */ - public function clearInstances() { + public function clearInstances() + { $this->instances = []; } @@ -53,14 +58,16 @@ public function clearInstances() { /** * @inheritDoc */ - public function defaultRule() { - return $this->rule('*'); + public function defaultRule() + { + return $this->rule("*"); } /** * @inheritDoc */ - public function rule($id) { + public function rule($id) + { $id = $this->normalizeID($id); if (!isset($this->rules[$id])) { @@ -75,7 +82,8 @@ public function rule($id) { /** * @inheritDoc */ - public function hasRule(string $id): bool { + public function hasRule(string $id): bool + { $id = $this->normalizeID($id); return !empty($this->rules[$id]); } @@ -83,35 +91,46 @@ public function hasRule(string $id): bool { /** * @inheritDoc */ - public function getClass(): string { - return empty($this->currentRule['class']) ? '' : $this->currentRule['class']; + public function getClass(): string + { + return empty($this->currentRule["class"]) + ? "" + : $this->currentRule["class"]; } /** * @inheritDoc */ - public function setClass(string $className) { - $this->currentRule['class'] = $className; + public function setClass(string $className) + { + $this->currentRule["class"] = $className; return $this; } /** * @inheritDoc */ - public function getAliasOf(): string { - return empty($this->currentRule['aliasOf']) ? '' : $this->currentRule['aliasOf']; + public function getAliasOf(): string + { + return empty($this->currentRule["aliasOf"]) + ? "" + : $this->currentRule["aliasOf"]; } /** * @inheritDoc */ - public function setAliasOf(string $alias) { + public function setAliasOf(string $alias) + { $alias = $this->normalizeID($alias); if ($alias === $this->currentRuleName) { - trigger_error("You cannot set alias '$alias' to itself.", E_USER_NOTICE); + trigger_error( + "You cannot set alias '$alias' to itself.", + E_USER_NOTICE + ); } else { - $this->currentRule['aliasOf'] = $alias; + $this->currentRule["aliasOf"] = $alias; } return $this; } @@ -119,14 +138,18 @@ public function setAliasOf(string $alias) { /** * @inheritDoc */ - public function addAlias(string ...$alias) { + public function addAlias(string ...$alias) + { foreach ($alias as $name) { $name = $this->normalizeID($name); if ($name === $this->currentRuleName) { - trigger_error("Tried to set alias '$name' to self.", E_USER_NOTICE); + trigger_error( + "Tried to set alias '$name' to self.", + E_USER_NOTICE + ); } else { - $this->rules[$name]['aliasOf'] = $this->currentRuleName; + $this->rules[$name]["aliasOf"] = $this->currentRuleName; } } return $this; @@ -135,25 +158,36 @@ public function addAlias(string ...$alias) { /** * @inheritDoc */ - public function removeAlias(string $alias) { + public function removeAlias(string $alias) + { $alias = $this->normalizeID($alias); - if (!empty($this->rules[$alias]['aliasOf']) && $this->rules[$alias]['aliasOf'] !== $this->currentRuleName) { - trigger_error("Alias '$alias' does not point to the current rule.", E_USER_NOTICE); + if ( + !empty($this->rules[$alias]["aliasOf"]) && + $this->rules[$alias]["aliasOf"] !== $this->currentRuleName + ) { + trigger_error( + "Alias '$alias' does not point to the current rule.", + E_USER_NOTICE + ); } - unset($this->rules[$alias]['aliasOf']); + unset($this->rules[$alias]["aliasOf"]); return $this; } /** * @inheritDoc */ - public function getAliases(): array { + public function getAliases(): array + { $result = []; foreach ($this->rules as $name => $rule) { - if (!empty($rule['aliasOf']) && $rule['aliasOf'] === $this->currentRuleName) { + if ( + !empty($rule["aliasOf"]) && + $rule["aliasOf"] === $this->currentRuleName + ) { $result[] = $name; } } @@ -164,60 +198,72 @@ public function getAliases(): array { /** * @inheritDoc */ - public function getFactory(): ?callable { - return isset($this->currentRule['factory']) ? $this->currentRule['factory'] : null; + public function getFactory(): ?callable + { + return isset($this->currentRule["factory"]) + ? $this->currentRule["factory"] + : null; } /** * @inheritDoc */ - public function setFactory(?callable $factory = null) { - $this->currentRule['factory'] = $factory; + public function setFactory(?callable $factory = null) + { + $this->currentRule["factory"] = $factory; return $this; } /** * @inheritDoc */ - public function isShared(): bool { - return !empty($this->currentRule['shared']); + public function isShared(): bool + { + return !empty($this->currentRule["shared"]); } /** * @inheritDoc */ - public function setShared(bool $shared) { - $this->currentRule['shared'] = $shared; + public function setShared(bool $shared) + { + $this->currentRule["shared"] = $shared; return $this; } /** * @inheritDoc */ - public function getInherit(): bool { - return !empty($this->currentRule['inherit']); + public function getInherit(): bool + { + return !empty($this->currentRule["inherit"]); } /** * @inheritDoc */ - public function setInherit(bool $inherit) { - $this->currentRule['inherit'] = $inherit; + public function setInherit(bool $inherit) + { + $this->currentRule["inherit"] = $inherit; return $this; } /** * @inheritDoc */ - public function getConstructorArgs(): array { - return empty($this->currentRule['constructorArgs']) ? [] : $this->currentRule['constructorArgs']; + public function getConstructorArgs(): array + { + return empty($this->currentRule["constructorArgs"]) + ? [] + : $this->currentRule["constructorArgs"]; } /** * @inheritDoc */ - public function setConstructorArgs(array $args) { - $this->currentRule['constructorArgs'] = $args; + public function setConstructorArgs(array $args) + { + $this->currentRule["constructorArgs"] = $args; return $this; } @@ -231,7 +277,8 @@ public function setConstructorArgs(array $args) { * @param mixed $instance This instance. * @return $this */ - public function setInstance(string $name, $instance) { + public function setInstance(string $name, $instance) + { $this->instances[$this->normalizeID($name)] = $instance; return $this; } @@ -239,8 +286,9 @@ public function setInstance(string $name, $instance) { /** * @inheritDoc */ - public function addCall(string $method, array $args = []) { - $this->currentRule['calls'][] = [$method, $args]; + public function addCall(string $method, array $args = []) + { + $this->currentRule["calls"][] = [$method, $args]; // Something added a rule. If we have any existing factories make sure we clear them. if (isset($this->factories[$this->currentRuleName])) { @@ -266,7 +314,8 @@ public function addCall(string $method, array $args = []) { * * @return T|mixed Entry. */ - public function getArgs($id, array $args = []) { + public function getArgs($id, array $args = []) + { $id = $this->normalizeID($id); if (isset($this->instances[$id])) { @@ -279,9 +328,9 @@ public function getArgs($id, array $args = []) { return $this->factories[$id]($args); } - if (!empty($this->rules[$id]['aliasOf'])) { + if (!empty($this->rules[$id]["aliasOf"])) { // This rule references another rule. - return $this->getArgs($this->rules[$id]['aliasOf'], $args); + return $this->getArgs($this->rules[$id]["aliasOf"], $args); } // The factory or instance isn't registered so do that now. @@ -297,7 +346,8 @@ public function getArgs($id, array $args = []) { * @return mixed Returns the result of the callback. * @throws ContainerException Throws an exception if the callback cannot be understood. */ - public function call(callable $callback, array $args = []) { + public function call(callable $callback, array $args = []) + { $instance = null; if (is_array($callback)) { @@ -306,14 +356,18 @@ public function call(callable $callback, array $args = []) { if (is_object($callback[0])) { $instance = $callback[0]; } - } elseif (is_string($callback) || ($callback instanceof \Closure)) { + } elseif (is_string($callback) || $callback instanceof \Closure) { $function = new \ReflectionFunction($callback); } else { // Assume we are an invokable. - $function = new \ReflectionMethod($callback, '__invoke'); - $callback = [$callback, '__invoke']; + $function = new \ReflectionMethod($callback, "__invoke"); + $callback = [$callback, "__invoke"]; } - $args = $this->resolveArgs($this->makeDefaultArgs($function, $args), [], $instance); + $args = $this->resolveArgs( + $this->makeDefaultArgs($function, $args), + [], + $instance + ); return call_user_func_array($callback, $args); } @@ -325,10 +379,13 @@ public function call(callable $callback, array $args = []) { * * @return boolean` */ - public function has($id) { + public function has(string $id): bool + { $id = $this->normalizeID($id); - return isset($this->instances[$id]) || !empty($this->rules[$id]) || class_exists($id); + return isset($this->instances[$id]) || + !empty($this->rules[$id]) || + class_exists($id); } /** @@ -338,7 +395,8 @@ public function has($id) { * * @return bool */ - public function hasInstance($id) { + public function hasInstance($id) + { $id = $this->normalizeID($id); return isset($this->instances[$id]); @@ -355,7 +413,8 @@ public function hasInstance($id) { * * @return T|mixed Entry. */ - public function get($id) { + public function get($id) + { return $this->getArgs($id); } @@ -370,15 +429,14 @@ public function get($id) { * @return array Returns the cloned array. * @see http://stackoverflow.com/a/17729234 */ - private function arrayClone(array $array) { + private function arrayClone(array $array) + { return array_map(function ($element) { - return ((is_array($element)) + return is_array($element) ? $this->arrayClone($element) - : ((is_object($element)) + : (is_object($element) ? clone $element - : $element - ) - ); + : $element); }, $array); } @@ -388,8 +446,9 @@ private function arrayClone(array $array) { * @param string $id The ID to normalize. * @return string Returns a normalized ID as a string. */ - private function normalizeID($id) { - return ltrim($id, '\\'); + private function normalizeID($id) + { + return ltrim($id, "\\"); } /** @@ -398,21 +457,30 @@ private function normalizeID($id) { * @param string $nid A normalized ID. * @return array Returns an array representing a rule. */ - private function makeRule($nid) { + private function makeRule($nid) + { $rule = isset($this->rules[$nid]) ? $this->rules[$nid] : []; if (class_exists($nid)) { - for ($class = get_parent_class($nid); !empty($class); $class = get_parent_class($class)) { + for ( + $class = get_parent_class($nid); + !empty($class); + $class = get_parent_class($class) + ) { // Don't add the rule if it doesn't say to inherit. - if (!isset($this->rules[$class]) || (isset($this->rules[$class]['inherit']) && !$this->rules[$class]['inherit'])) { + if ( + !isset($this->rules[$class]) || + (isset($this->rules[$class]["inherit"]) && + !$this->rules[$class]["inherit"]) + ) { continue; } $rule += $this->rules[$class]; } // Add the default rule. - if (!empty($this->rules['*']['inherit'])) { - $rule += $this->rules['*']; + if (!empty($this->rules["*"]["inherit"])) { + $rule += $this->rules["*"]; } // Add interface calls to the rule. @@ -421,29 +489,39 @@ private function makeRule($nid) { if (isset($this->rules[$interface])) { $interfaceRule = $this->rules[$interface]; - if (isset($interfaceRule['inherit']) && $interfaceRule['inherit'] === false) { + if ( + isset($interfaceRule["inherit"]) && + $interfaceRule["inherit"] === false + ) { continue; } - if (!isset($rule['shared']) && isset($interfaceRule['shared'])) { - $rule['shared'] = $interfaceRule['shared']; + if ( + !isset($rule["shared"]) && + isset($interfaceRule["shared"]) + ) { + $rule["shared"] = $interfaceRule["shared"]; } - if (!isset($rule['constructorArgs']) && isset($interfaceRule['constructorArgs'])) { - $rule['constructorArgs'] = $interfaceRule['constructorArgs']; + if ( + !isset($rule["constructorArgs"]) && + isset($interfaceRule["constructorArgs"]) + ) { + $rule["constructorArgs"] = + $interfaceRule["constructorArgs"]; } - if (!empty($interfaceRule['calls'])) { - $rule['calls'] = array_merge( - isset($rule['calls']) ? $rule['calls'] : [], - $interfaceRule['calls'] + if (!empty($interfaceRule["calls"])) { + $rule["calls"] = array_merge( + isset($rule["calls"]) ? $rule["calls"] : [], + $interfaceRule["calls"] ); } } } - } elseif (!empty($this->rules['*']['inherit'])) { + } elseif (!empty($this->rules["*"]["inherit"])) { // Add the default rule. - $rule += $this->rules['*']; + $rule += $this->rules["*"]; } return $rule; @@ -457,18 +535,25 @@ private function makeRule($nid) { * @return callable Returns a function that when called will create a new instance of the class. * @throws NotFoundException No entry was found for this identifier. */ - private function makeFactory($nid, array $rule) { - $className = empty($rule['class']) ? $nid : $rule['class']; + private function makeFactory($nid, array $rule) + { + $className = empty($rule["class"]) ? $nid : $rule["class"]; - if (!empty($rule['factory'])) { + if (!empty($rule["factory"])) { // The instance is created with a user-supplied factory function. - $callback = $rule['factory']; + $callback = $rule["factory"]; $function = $this->reflectCallback($callback); if ($function->getNumberOfParameters() > 0) { - $callbackArgs = $this->makeDefaultArgs($function, (array)$rule['constructorArgs']); + $callbackArgs = $this->makeDefaultArgs( + $function, + (array) $rule["constructorArgs"] + ); $factory = function ($args) use ($callback, $callbackArgs) { - return call_user_func_array($callback, $this->resolveArgs($callbackArgs, $args)); + return call_user_func_array( + $callback, + $this->resolveArgs($callbackArgs, $args) + ); }; } else { $factory = $callback; @@ -481,33 +566,46 @@ private function makeFactory($nid, array $rule) { } else { // The instance is created by newing up a class. if (!class_exists($className)) { - throw new NotFoundException("Class $className does not exist.", 404); + throw new NotFoundException( + "Class $className does not exist.", + 404 + ); } $class = new \ReflectionClass($className); $constructor = $class->getConstructor(); if ($constructor && $constructor->getNumberOfParameters() > 0) { - $constructorArgs = $this->makeDefaultArgs($constructor, (array)$rule['constructorArgs']); + $constructorArgs = $this->makeDefaultArgs( + $constructor, + (array) $rule["constructorArgs"] + ); $factory = function ($args) use ($className, $constructorArgs) { - return new $className(...array_values($this->resolveArgs($constructorArgs, $args))); + return new $className( + ...array_values( + $this->resolveArgs($constructorArgs, $args) + ) + ); }; } else { $factory = function () use ($className) { - return new $className; + return new $className(); }; } } // Add calls to the factory. - if (isset($class) && !empty($rule['calls'])) { + if (isset($class) && !empty($rule["calls"])) { $calls = []; // Generate the calls array. - foreach ($rule['calls'] as $call) { + foreach ($rule["calls"] as $call) { [$methodName, $args] = $call; $method = $class->getMethod($methodName); - $calls[] = [$methodName, $this->makeDefaultArgs($method, $args)]; + $calls[] = [ + $methodName, + $this->makeDefaultArgs($method, $args), + ]; } // Wrap the factory in one that makes the calls. @@ -519,11 +617,12 @@ private function makeFactory($nid, array $rule) { foreach ($calls as $call) { [$methodName, $defaultArgs] = $call; - $finalArgs = $this->resolveArgs($defaultArgs, [], $instance); - call_user_func_array( - [$instance, $methodName], - $finalArgs + $finalArgs = $this->resolveArgs( + $defaultArgs, + [], + $instance ); + call_user_func_array([$instance, $methodName], $finalArgs); } return $instance; @@ -544,20 +643,27 @@ private function makeFactory($nid, array $rule) { * @return object Returns the the new instance. * @throws NotFoundException Throws an exception if the class does not exist. */ - private function createSharedInstance($nid, array $rule, array $args) { - if (!empty($rule['factory'])) { + private function createSharedInstance($nid, array $rule, array $args) + { + if (!empty($rule["factory"])) { // The instance is created with a user-supplied factory function. - $callback = $rule['factory']; + $callback = $rule["factory"]; $function = $this->reflectCallback($callback); if ($function->getNumberOfParameters() > 0) { $callbackArgs = $this->resolveArgs( - $this->makeDefaultArgs($function, (array)$rule['constructorArgs']), + $this->makeDefaultArgs( + $function, + (array) $rule["constructorArgs"] + ), $args ); $this->instances[$nid] = null; // prevent cyclic dependency from infinite loop. - $this->instances[$nid] = $instance = call_user_func_array($callback, $callbackArgs); + $this->instances[$nid] = $instance = call_user_func_array( + $callback, + $callbackArgs + ); } else { $this->instances[$nid] = $instance = $callback(); } @@ -567,9 +673,12 @@ private function createSharedInstance($nid, array $rule, array $args) { $class = new \ReflectionClass(get_class($instance)); } } else { - $className = empty($rule['class']) ? $nid : $rule['class']; + $className = empty($rule["class"]) ? $nid : $rule["class"]; if (!class_exists($className)) { - throw new NotFoundException("Class $className does not exist.", 404); + throw new NotFoundException( + "Class $className does not exist.", + 404 + ); } $class = new \ReflectionClass($className); $constructor = $class->getConstructor(); @@ -577,10 +686,15 @@ private function createSharedInstance($nid, array $rule, array $args) { if ($constructor && $constructor->getNumberOfParameters() > 0) { try { // Instantiate the object first so that this instance can be used for cyclic dependencies. - $this->instances[$nid] = $instance = $class->newInstanceWithoutConstructor(); + $this->instances[ + $nid + ] = $instance = $class->newInstanceWithoutConstructor(); $constructorArgs = $this->resolveArgs( - $this->makeDefaultArgs($constructor, (array)$rule['constructorArgs']), + $this->makeDefaultArgs( + $constructor, + (array) $rule["constructorArgs"] + ), $args ); $constructor->invokeArgs($instance, $constructorArgs); @@ -589,13 +703,13 @@ private function createSharedInstance($nid, array $rule, array $args) { throw $ex; } } else { - $this->instances[$nid] = $instance = new $class->name; + $this->instances[$nid] = $instance = new $class->name(); } } // Call subsequent calls on the new object. - if (isset($class) && !empty($rule['calls'])) { - foreach ($rule['calls'] as $call) { + if (isset($class) && !empty($rule["calls"])) { + foreach ($rule["calls"] as $call) { [$methodName, $args] = $call; $method = $class->getMethod($methodName); @@ -615,7 +729,6 @@ private function createSharedInstance($nid, array $rule, array $args) { return $instance; } - /** * Find the class implemented by an ID. * @@ -624,13 +737,14 @@ private function createSharedInstance($nid, array $rule, array $args) { * @param string $nid The normalized ID to look up. * @return string|null Returns the name of the class associated with the rule or **null** if one could not be found. */ - private function findRuleClass($nid) { + private function findRuleClass($nid) + { if (!isset($this->rules[$nid])) { return null; - } elseif (!empty($this->rules[$nid]['aliasOf'])) { - return $this->findRuleClass($this->rules[$nid]['aliasOf']); - } elseif (!empty($this->rules[$nid]['class'])) { - return $this->rules[$nid]['class']; + } elseif (!empty($this->rules[$nid]["aliasOf"])) { + return $this->findRuleClass($this->rules[$nid]["aliasOf"]); + } elseif (!empty($this->rules[$nid]["class"])) { + return $this->rules[$nid]["class"]; } return null; @@ -644,7 +758,10 @@ private function findRuleClass($nid) { * @return array Returns an array in the form `name => defaultValue`. * @throws NotFoundException If a non-optional class param is reflected and does not exist. */ - private function makeDefaultArgs(\ReflectionFunctionAbstract $function, array $ruleArgs) { + private function makeDefaultArgs( + \ReflectionFunctionAbstract $function, + array $ruleArgs + ) { $ruleArgs = array_change_key_case($ruleArgs); $result = []; @@ -653,16 +770,25 @@ private function makeDefaultArgs(\ReflectionFunctionAbstract $function, array $r $name = strtolower($param->name); $reflectedClass = $reflectionType = null; try { - if(class_exists(\ReflectionUnionType::class) === true){ + if (class_exists(\ReflectionUnionType::class) === true) { $reflectionType = $param->getType(); - if(!empty($reflectionType) && !$reflectionType instanceof \ReflectionUnionType){ - if(method_exists($reflectionType, 'isBuiltin') && !$reflectionType->isBuiltin() && method_exists($reflectionType, 'getName')) - $reflectedClass = new \ReflectionClass($reflectionType->getName()); + if ( + !empty($reflectionType) && + !$reflectionType instanceof \ReflectionUnionType + ) { + if ( + method_exists($reflectionType, "isBuiltin") && + !$reflectionType->isBuiltin() && + method_exists($reflectionType, "getName") + ) { + $reflectedClass = new \ReflectionClass( + $reflectionType->getName() + ); + } } - }else{ - $reflectedClass = $param->getClass(); + } else { + $reflectedClass = $param->getClass(); } - } catch (\ReflectionException $e) { // If the class is not found in the autoloader a reflection exception is thrown. // Unless the parameter is optional we will want to rethrow. @@ -671,7 +797,9 @@ private function makeDefaultArgs(\ReflectionFunctionAbstract $function, array $r $functionName = self::functionName($function); throw new NotFoundException( - "Could not find class for required parameter $typeName for " . $functionName . "in the autoloader.", + "Could not find class for required parameter $typeName for " . + $functionName . + "in the autoloader.", 500, $e ); @@ -681,9 +809,20 @@ private function makeDefaultArgs(\ReflectionFunctionAbstract $function, array $r $hasOrdinalRule = isset($ruleArgs[$pos]); /*if dependency is autowired and one of the dependency is a required union type parameter which is not configured we should throw an error */ - if(class_exists(ReflectionUnionType::class) && $reflectionType instanceof \ReflectionUnionType && (!$hasOrdinalRule || empty($ruleArgs[$name])) && !$param->isOptional()) { - throw new ContainerException("The required parameter " . $param->name . - " for class " . self::functionName($function) ." is not defined", 500); + if ( + class_exists(ReflectionUnionType::class) && + $reflectionType instanceof \ReflectionUnionType && + (!$hasOrdinalRule || empty($ruleArgs[$name])) && + !$param->isOptional() + ) { + throw new ContainerException( + "The required parameter " . + $param->name . + " for class " . + self::functionName($function) . + " is not defined", + 500 + ); } $isMatchingOrdinalReference = false; $isMatchingOrdinalInstance = false; @@ -696,7 +835,11 @@ private function makeDefaultArgs(\ReflectionFunctionAbstract $function, array $r $ruleClass = end($ruleClass); } - if (($resolvedRuleClass = $this->findRuleClass($ruleClass)) !== null) { + if ( + ($resolvedRuleClass = $this->findRuleClass( + $ruleClass + )) !== null + ) { $ruleClass = $resolvedRuleClass; } @@ -708,27 +851,31 @@ private function makeDefaultArgs(\ReflectionFunctionAbstract $function, array $r ); } elseif (is_object($ordinalRule)) { // The argument is an instance that matches the type hint. - $isMatchingOrdinalInstance = is_a($ordinalRule, $reflectedClass->getName()); + $isMatchingOrdinalInstance = is_a( + $ordinalRule, + $reflectedClass->getName() + ); } } if (array_key_exists($name, $ruleArgs)) { $value = $ruleArgs[$name]; } elseif ( - $reflectedClass - && $hasOrdinalRule - && ($isMatchingOrdinalReference|| $isMatchingOrdinalInstance) + $reflectedClass && + $hasOrdinalRule && + ($isMatchingOrdinalReference || $isMatchingOrdinalInstance) ) { $value = $ruleArgs[$pos]; $pos++; - } elseif ($reflectedClass - && ( - $reflectedClass->isInstantiable() - || isset($this->rules[$reflectedClass->name]) - || array_key_exists($reflectedClass->name, $this->instances) - ) + } elseif ( + $reflectedClass && + ($reflectedClass->isInstantiable() || + isset($this->rules[$reflectedClass->name]) || + array_key_exists($reflectedClass->name, $this->instances)) ) { - $value = new DefaultReference($this->normalizeID($reflectedClass->name)); + $value = new DefaultReference( + $this->normalizeID($reflectedClass->name) + ); } elseif ($hasOrdinalRule) { $value = $ruleArgs[$pos]; $pos++; @@ -757,14 +904,17 @@ private function makeDefaultArgs(\ReflectionFunctionAbstract $function, array $r * @return array Returns an array suitable to be applied to a function call. * @throws MissingArgumentException Throws an exception when a required parameter is missing. */ - private function resolveArgs(array $defaultArgs, array $args, $instance = null) { + private function resolveArgs( + array $defaultArgs, + array $args, + $instance = null + ) { // First resolve all passed arguments so their types are known. - $args = array_map( - function ($arg) use ($instance) { - return $arg instanceof ReferenceInterface ? $arg->resolve($this, $instance) : $arg; - }, - array_change_key_case($args) - ); + $args = array_map(function ($arg) use ($instance) { + return $arg instanceof ReferenceInterface + ? $arg->resolve($this, $instance) + : $arg; + }, array_change_key_case($args)); $pos = 0; foreach ($defaultArgs as $name => &$default) { @@ -775,28 +925,23 @@ function ($arg) use ($instance) { */ $name = strtolower($name); $class = null; - if(isset($args[$pos]) && is_object($default)) { - if(method_exists($default, 'getClass')) { + if (isset($args[$pos]) && is_object($default)) { + if (method_exists($default, "getClass")) { $class = $default->getClass(); - }elseif(method_exists($default, 'getName')){ + } elseif (method_exists($default, "getName")) { $class = $default->getName(); - }else{ + } else { $class = null; } - } if (array_key_exists($name, $args)) { // This is a named arg and should be used. $value = $args[$name]; - } elseif (isset($args[$pos]) - && ( - !($default instanceof DefaultReference) - || empty($class) - || is_a( - $args[$pos], - $class - ) - ) + } elseif ( + isset($args[$pos]) && + (!($default instanceof DefaultReference) || + empty($class) || + is_a($args[$pos], $class)) ) { // There is an arg at this position and it's the same type as the default arg or the default arg is typeless. $value = $args[$pos]; @@ -825,11 +970,12 @@ function ($arg) use ($instance) { * @param array $args Additional arguments to pass to the constructor. * @return object Returns an object instance. */ - private function createInstance($nid, array $args) { + private function createInstance($nid, array $args) + { $rule = $this->makeRule($nid); // Cache the instance or its factory for future use. - if (empty($rule['shared'])) { + if (empty($rule["shared"])) { $factory = $this->makeFactory($nid, $rule); $instance = $factory($args); $this->factories[$nid] = $factory; @@ -845,27 +991,32 @@ private function createInstance($nid, array $args) { * @param callable $callback The callback to reflect. * @return \ReflectionFunctionAbstract Returns the reflection function for the callback. */ - private function reflectCallback(callable $callback) { + private function reflectCallback(callable $callback) + { if (is_array($callback)) { return new \ReflectionMethod($callback[0], $callback[1]); } elseif (is_string($callback) || $callback instanceof \Closure) { return new \ReflectionFunction($callback); } else { - return new \ReflectionMethod($callback, '__invoke'); + return new \ReflectionMethod($callback, "__invoke"); } } - /** * Return the name of a function to aid debugging. * * @param \ReflectionFunctionAbstract $function * @return string */ - protected static function functionName(\ReflectionFunctionAbstract $function): string { - $functionName = $function->getName() . '()'; + protected static function functionName( + \ReflectionFunctionAbstract $function + ): string { + $functionName = $function->getName() . "()"; if ($function instanceof \ReflectionMethod) { - $functionName = $function->getDeclaringClass()->getName() . '::' . $functionName; + $functionName = + $function->getDeclaringClass()->getName() . + "::" . + $functionName; } return $functionName; } @@ -876,7 +1027,9 @@ protected static function functionName(\ReflectionFunctionAbstract $function): s * @param \ReflectionParameter $param * @return string */ - protected static function parameterTypeName(\ReflectionParameter $param): string { + protected static function parameterTypeName( + \ReflectionParameter $param + ): string { $type = $param->getType(); if ($type instanceof \ReflectionNamedType) { $name = $type->getName(); diff --git a/src/ContainerConfigurationInterface.php b/src/ContainerConfigurationInterface.php index 8d81a03..df1f085 100644 --- a/src/ContainerConfigurationInterface.php +++ b/src/ContainerConfigurationInterface.php @@ -12,8 +12,8 @@ * * No methods for instantiation are provided. */ -interface ContainerConfigurationInterface { - +interface ContainerConfigurationInterface +{ /** * Set the current rule. * @@ -171,4 +171,3 @@ public function addCall(string $method, array $args = []); */ public function hasRule(string $id): bool; } - diff --git a/src/DefaultReference.php b/src/DefaultReference.php index 51a6d1c..a4aa913 100644 --- a/src/DefaultReference.php +++ b/src/DefaultReference.php @@ -11,7 +11,8 @@ /** * Used internally. */ -class DefaultReference implements ReferenceInterface { +class DefaultReference implements ReferenceInterface +{ /** * @var string */ @@ -22,7 +23,8 @@ class DefaultReference implements ReferenceInterface { * * @param string $class The name of the reference. */ - public function __construct(string $class) { + public function __construct(string $class) + { $this->setClass($class); } @@ -31,7 +33,8 @@ public function __construct(string $class) { * * @return string Returns the name of the reference. */ - public function getClass(): string { + public function getClass(): string + { return $this->class; } @@ -40,14 +43,16 @@ public function getClass(): string { * * @param string $class The name of the reference. */ - public function setClass(string $class) { + public function setClass(string $class) + { $this->class = $class; } /** * {@inheritdoc} */ - public function resolve(Container $container, $instance = null) { + public function resolve(Container $container, $instance = null) + { return $container->get($this->class); } } diff --git a/src/Reference.php b/src/Reference.php index 5c2d400..b1e1728 100644 --- a/src/Reference.php +++ b/src/Reference.php @@ -10,7 +10,8 @@ /** * A reference to another entry in a {@link Container}. */ -class Reference implements ReferenceInterface { +class Reference implements ReferenceInterface +{ /** * @var string|array */ @@ -27,7 +28,8 @@ class Reference implements ReferenceInterface { * @param string|array $name The name of the reference. * @param array $args Constructor arguments for the reference. */ - public function __construct($name, array $args = []) { + public function __construct($name, array $args = []) + { $this->setName($name); $this->setArgs($args); } @@ -37,7 +39,8 @@ public function __construct($name, array $args = []) { * * @return string|array Returns the name of the reference. */ - public function getName() { + public function getName() + { return $this->name; } @@ -46,14 +49,16 @@ public function getName() { * * @param string|array $name The name of the reference. */ - public function setName($name) { + public function setName($name) + { $this->name = $name; } /** * {@inheritdoc} */ - public function resolve(Container $container, $instance = null) { + public function resolve(Container $container, $instance = null) + { if (empty($this->name)) { return null; } elseif (is_string($this->name)) { @@ -72,7 +77,8 @@ public function resolve(Container $container, $instance = null) { * * @return array Returns the arguments. */ - public function getArgs() { + public function getArgs() + { return $this->args; } @@ -82,7 +88,8 @@ public function getArgs() { * @param array $args An array of arguments. * @return $this */ - public function setArgs($args) { + public function setArgs($args) + { $this->args = $args; return $this; } diff --git a/src/ReferenceInterface.php b/src/ReferenceInterface.php index 8749182..27d67e2 100644 --- a/src/ReferenceInterface.php +++ b/src/ReferenceInterface.php @@ -7,17 +7,17 @@ namespace Garden\Container; - /** * Container args can implement this interface to dynamically resolve in interesting ways. */ -interface ReferenceInterface { +interface ReferenceInterface +{ /** * Resolve the reference. * * @param Container $container The container resolving the reference. - * @param mixed $instance If the reference is being resolved on an already instantiated object it will be passed here. + * @param mixed|null $instance If the reference is being resolved on an already instantiated object it will be passed here. * @return mixed Returns the resolved reference. */ - public function resolve(Container $container, $instance = null); -} \ No newline at end of file + public function resolve(Container $container, mixed $instance = null); +} diff --git a/src/RequiredParameter.php b/src/RequiredParameter.php index e9d6ae0..dec7aaa 100644 --- a/src/RequiredParameter.php +++ b/src/RequiredParameter.php @@ -11,7 +11,8 @@ /** * A placeholder for a required parameter. */ -class RequiredParameter extends DefaultReference { +class RequiredParameter extends DefaultReference +{ private $parameter; private $function; @@ -20,34 +21,42 @@ class RequiredParameter extends DefaultReference { * * @param \ReflectionParameter $param The required parameter. */ - public function __construct(\ReflectionParameter $param) { - + public function __construct(\ReflectionParameter $param) + { $classString = ""; - if(class_exists(\ReflectionUnionType::class)){ + if (class_exists(\ReflectionUnionType::class)) { $reflectionType = $param->getType(); - if(!empty($reflectionType) && !$reflectionType instanceof \ReflectionUnionType && - method_exists($reflectionType, 'isBuiltin') && !$reflectionType->isBuiltin() - && method_exists($reflectionType, 'getName')){ - $classString = $reflectionType->getName(); + if ( + !empty($reflectionType) && + !$reflectionType instanceof \ReflectionUnionType && + method_exists($reflectionType, "isBuiltin") && + !$reflectionType->isBuiltin() && + method_exists($reflectionType, "getName") + ) { + $classString = $reflectionType->getName(); } - }else{ - $classString = $param->getClass() ? $param->getClass()->name : ''; + } else { + $classString = $param->getClass() ? $param->getClass()->name : ""; } parent::__construct($classString); $this->parameter = $param->name; - $this->function = ($param->getDeclaringClass() ? $param->getDeclaringClass()->name.'::' : ''). - $param->getDeclaringFunction()->name.'()'; + $this->function = + ($param->getDeclaringClass() + ? $param->getDeclaringClass()->name . "::" + : "") . + $param->getDeclaringFunction()->name . + "()"; } - /** * Get the name. * * @return string Returns the name. */ - public function getParameter() { + public function getParameter() + { return $this->parameter; } @@ -56,7 +65,8 @@ public function getParameter() { * * @return string Returns the function. */ - public function getFunction() { + public function getFunction() + { return $this->function; } @@ -65,7 +75,11 @@ public function getFunction() { * * @throws MissingArgumentException Always throws an exception. */ - public function resolve(Container $container, $instance = null) { - throw new MissingArgumentException($this->getParameter(), $this->getFunction()); + public function resolve(Container $container, $instance = null) + { + throw new MissingArgumentException( + $this->getParameter(), + $this->getFunction() + ); } }