From 1feed0e4d99b7db64fb8918a47cd879fb354b9cc Mon Sep 17 00:00:00 2001 From: Sohel Amin Date: Sat, 19 Mar 2016 13:19:53 +0600 Subject: [PATCH 1/2] re-written --- README.md | 27 +++---- src/Container.php | 187 ++++++++++++++++++++++++++++------------------ 2 files changed, 127 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index 92ed24c..ee4cb27 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,15 @@ Dependency Injection Container ## Installation -1. Run +1. Run ``` composer require appzcoder/container:"dev-master" ``` - + 2. Add bellow lines to your script - ```php - require 'vendor/autoload.php'; - ``` + ```php + require 'vendor/autoload.php'; + ``` ## Usage @@ -41,35 +41,36 @@ class FooBar { } // No dependencies // Instantiate the container -$container = Appzcoder\Container\Container::getInstance(); +$container = new Appzcoder\Container\Container(); // Registering class with dependencies -$container->make('Foo'); +$container->set('Foo'); // Registering class with another name -$container->make('foo', 'Bar'); +$container->set('foo', 'Bar'); // Binding a closure object with a name -$container->make('FooBar', function () { +$container->setInstance('FooBar', function () { return new FooBar(); }); // Registering class with parameters -$container->make('Foo', 'Foo', ['param 1', 'param 2']); +$container->set('Foo', 'Foo', ['param 1', 'param 2']); // Binding an instance with a name $instance = new FooBar(); -$container->instance('FooBar', $instance); +$container->setInstance('FooBar', $instance); // Binding an instance/object with container's array $container['FooBar'] = new FooBar(); // Calling a setter method with dependencies -$instance = $container->make('Foo', 'Foo', ['param 1', 'param 2']); +$container->set('Foo', 'Foo', ['param 1', 'param 2']); +$instance = $container->get('Foo'); $container->call([$instance, 'setterMethod'], ['param 1', 'param 2']); // Accessing container or getting instances -$instance1 = $container->make('Foo'); +$instance1 = $container->get('Foo'); $instance2 = $container['Foo']; // For this should have registered or bounded "Foo" ``` diff --git a/src/Container.php b/src/Container.php index 832cc4f..2b67959 100644 --- a/src/Container.php +++ b/src/Container.php @@ -4,19 +4,19 @@ use ArrayAccess; use Closure; +use Exception; use ReflectionClass; use ReflectionFunction; use ReflectionMethod; class Container implements ArrayAccess { - /** - * Instance of this class. + * Container's definitions. * - * @var static + * @var array */ - protected static $instance; + protected $definitions = []; /** * Container's instances. @@ -26,56 +26,120 @@ class Container implements ArrayAccess protected $instances = []; /** - * Let the container access globally. + * Container's parameters. + * + * @var array + */ + protected $parameters = []; + + /** + * Set/Register a class into this container. + * + * @param string $name + * @param string $name (optional) + * @param string $params (optional) * - * @return static + * @return void */ - public static function getInstance() + public function set($name, $class = null, $params = []) { - if (null === static::$instance) { - static::$instance = new static(); + if (isset($name) && isset($class)) { + if (!class_exists($class)) { + throw new Exception("Your given [$class] is not exist."); + } else { + $this->definitions[$name] = $class; + + if (!empty($params)) { + $this->parameters[$name] = $params; + } + } + } else { + if (!class_exists($name)) { + throw new Exception("Your given [$name] is not exist."); + } else { + $this->definitions[$name] = $name; + } } - - return static::$instance; } /** - * Register class to create instances based on types. + * Get instance by given a class name or alias name. * * @param string $name - * @param \Closure|string|object $class - * @param array $parameters - * @return object + * + * @return object|null */ - public function make($name, $class = null, array $parameters = []) + public function get($name) { if (isset($this->instances[$name])) { return $this->instances[$name]; - } elseif (isset($class) && is_string($class) && class_exists($class)) { - return $this->instances[$name] = $this->build($class, $parameters); - } elseif (isset($class) && (is_object($class) || $class instanceof Closure)) { - return $this->instances[$name] = $class; + } elseif (isset($this->definitions[$name])) { + return $this->resolve($name); } else { - return $this->instances[$name] = $this->build($name, $parameters); + return null; } } + /** + * Resolve or instantiate object of given name. + * + * @param string $name + * + * @return object + */ + protected function resolve($name) + { + $class = $this->definitions[$name]; + + $parameters = isset($this->parameters[$name]) ? $this->parameters[$name] : []; + + $reflection = new ReflectionClass($class); + + if (!$reflection->isInstantiable()) { + throw new Exception("Your given [$class] is not instantiable."); + } + + $dependencies = $this->getDependencies($class); + $instances = []; + + foreach ($dependencies as $key => $class) { + $offset = is_string($key) ? $key : $class; + + if (isset($this->instances[$offset])) { + $instances[$offset] = $this->instances[$offset]; + } else { + $this->set($offset, $class); + + $instances[$offset] = $this->get($offset); + } + } + + $parameters = array_merge($instances, $parameters); + + $object = $reflection->newInstanceArgs($parameters); + + $this->setInstance($name, $object); + + return $object; + } + /** * Register an existing instance into this container. * * @param string $name * @param object $instance - * @return object + * + * @return void * * @throws \Exception */ - public function instance($name, $instance) + public function setInstance($name, $instance) { - if (is_object($instance)) { - return $this->instances[$name] = $instance; + if (is_object($instance) || $instance instanceof Closure) { + $this->instances[$name] = $instance; + } else { + throw new Exception("Your given instance is not an object or closure."); } - - throw new \Exception("Your given instance is not an object."); } /** @@ -83,47 +147,30 @@ public function instance($name, $instance) * * @param array $callback * @param array $parameters + * * @return void */ public function call($callback, array $parameters = []) { $dependencies = $this->getMethodDependencies($callback); - $instances = $this->makeBulk($dependencies); - $parameters = array_merge($instances, $parameters); - - return call_user_func_array($callback, $parameters); - } - /** - * Instantiate object of given class. - * - * @param string $class - * @param array $parameters - * @return object - * - * @throws \Exception - */ - protected function build($class, array $parameters = []) - { - $reflection = new ReflectionClass($class); + $instances = []; + foreach ($dependencies as $dependency) { + $this->set($dependency); - if (!$reflection->isInstantiable()) { - throw new \Exception("Your given [$class] is not instantiable."); + $instances[$dependency] = $this->resolve($dependency); } - $dependencies = $this->getDependencies($class); - $instances = $this->makeBulk($dependencies); $parameters = array_merge($instances, $parameters); - $object = $reflection->newInstanceArgs($parameters); - - return $object; + return call_user_func_array($callback, $parameters); } /** * Get all constructor's dependencies by given class. * * @param string $class + * * @return array */ protected function getDependencies($class) @@ -148,6 +195,7 @@ protected function getDependencies($class) * Get all dependencies of a given method. * * @param callable|array $callback + * * @return array */ protected function getMethodDependencies($callback) @@ -172,74 +220,65 @@ protected function getMethodDependencies($callback) } /** - * Make bulk instances of given array of classes. - * - * @param array $classes - * @return array - */ - public function makeBulk(array $classes) - { - $instances = []; - foreach ($classes as $key => $class) { - $offset = is_string($key) ? $key : $class; - $instances[$offset] = $this->make($offset, $class); - } - - return $instances; - } - - /** - * Clear all registered instances or classes. + * Clear the container. * * @return void */ public function clear() { + $this->definitions = []; $this->instances = []; + $this->parameters = []; } /** * Determine if a given offset exists. * * @param string $key + * * @return boolean */ public function offsetExists($key) { - return isset($this->instances[$key]); + return (isset($this->definitions[$key]) || isset($this->instances[$key])); } /** - * Get the value at a given offset. + * Get the value by given a offset. * * @param string $key + * * @return object */ public function offsetGet($key) { - return isset($this->instances[$key]) ? $this->instances[$key] : null; + return $this->get($key); } /** - * Set the value at a given offset. + * Set the value by given a offset. * * @param string $key * @param string $value + * * @return object */ public function offsetSet($key, $value) { - return $this->make($key, $value); + return $this->setInstance($key, $value); } /** * Unset the value at a given offset. * * @param string $key + * * @return object */ public function offsetUnset($key) { + unset($this->definitions[$key]); unset($this->instances[$key]); + unset($this->parameters[$key]); } } From 242c513d44fd0a74f2c5550b46fad06b4669c3ca Mon Sep 17 00:00:00 2001 From: Sohel Amin Date: Wed, 21 Mar 2018 10:43:01 +0600 Subject: [PATCH 2/2] Implement PSR-11 --- .gitignore | 3 +++ README.md | 8 ++++---- composer.json | 8 ++++---- src/Container.php | 31 ++++++++++++++++++++++--------- 4 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95d4d15 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_STORE +vendor +composer.lock diff --git a/README.md b/README.md index ee4cb27..df64b79 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Dependency Injection Container -Dependency Injection Container +# DI Container +> Dependency Injection Container ## Installation @@ -75,6 +75,6 @@ $instance2 = $container['Foo']; // For this should have registered or bounded "F ``` -##Author +## Author -[Sohel Amin](http://www.sohelamin.com) \ No newline at end of file +[Sohel Amin](http://www.sohelamin.com) diff --git a/composer.json b/composer.json index 93c7f8b..8d89ef5 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": [ "container", "di container" - ], + ], "authors": [ { "name": "Sohel Amin", @@ -14,13 +14,13 @@ } ], "require": { - "php": ">=5.4.0" + "php": ">=5.4.0", + "psr/container": "^1.0" }, "autoload": { "psr-4": { "Appzcoder\\Container\\": "src/" } }, - "minimum-stability": "dev", - "prefer-stable": true + "minimum-stability": "dev" } diff --git a/src/Container.php b/src/Container.php index 2b67959..2732af9 100644 --- a/src/Container.php +++ b/src/Container.php @@ -2,6 +2,7 @@ namespace Appzcoder\Container; +use Psr\Container\ContainerInterface; use ArrayAccess; use Closure; use Exception; @@ -9,7 +10,7 @@ use ReflectionFunction; use ReflectionMethod; -class Container implements ArrayAccess +class Container implements ContainerInterface, ArrayAccess { /** * Container's definitions. @@ -46,19 +47,19 @@ public function set($name, $class = null, $params = []) if (isset($name) && isset($class)) { if (!class_exists($class)) { throw new Exception("Your given [$class] is not exist."); - } else { - $this->definitions[$name] = $class; + } - if (!empty($params)) { - $this->parameters[$name] = $params; - } + $this->definitions[$name] = $class; + + if (!empty($params)) { + $this->parameters[$name] = $params; } } else { if (!class_exists($name)) { throw new Exception("Your given [$name] is not exist."); - } else { - $this->definitions[$name] = $name; } + + $this->definitions[$name] = $name; } } @@ -80,6 +81,18 @@ public function get($name) } } + /** + * Determine if a given offset exists. + * + * @param string $key + * + * @return boolean + */ + public function has($key) + { + return (isset($this->definitions[$key]) || isset($this->instances[$key])); + } + /** * Resolve or instantiate object of given name. * @@ -180,7 +193,7 @@ protected function getDependencies($class) $reflection = new ReflectionClass($class); $constructor = $reflection->getConstructor(); - if ($constructor !== null) { + if ($constructor) { foreach ($constructor->getParameters() as $param) { if ($param->getClass()) { $dependencies[] = $param->getClass()->getName();