5
\$\begingroup\$

I'm building a web application and is trying to make my code reusable. I've decided to create components that can be used outside this project.

Now I'm trying to create a simple DI container, one class, and I would like some help checking it out. I'm thinking to do something like this:

class Container
{
 protected static $_services = array();
 protected static $_shared = array();
 /**
 * Create and store a new service in the container.
 *
 * @param string $service Service identifier name.
 * @param mixed $params Service parameters, array or a Closure object.
 * @return object Ramverk\Framework\Container.
 */
 public function add($service, $params)
 {
 if (!is_object($params) && !is_array($params)) {
 throw new Exception("Service params must be a Closure object or an array.");
 }
 static::$_services[$service] = $params;
 return $this;
 }
 /**
 * Get a shared service object, will return the same object each time.
 *
 * @param string $service Name of the shared service to get.
 * @return object Shared service object.
 */
 public function get($service)
 {
 if (!array_key_exists($service, static::$_shared)) {
 static::$_shared[$service] = $this->getNew($service);
 }
 return static::$_shared[$service];
 }
 /**
 * Get a new instance of an existing service.
 *
 * @param string $service Name of the service to create.
 * @return object Create service object.
 */
 public function getNew($service)
 {
 // Make sure service has been added
 if (!array_key_exists($service, static::$_services)) {
 throw new Exception("Service '$service' not found");
 }
 // get container service
 $container = static::$_services[$service];
 // If service is wrapped in a Closure we invoke it
 if (is_object($container)) {
 return $container();
 }
 // Make sure we have a class to work with
 if (!isset($container['class'])) {
 throw new Exception("A class must be set in $service service");
 }
 // Get service key and remove key
 $class = $container['class'];
 unset($container['class']);
 // Check if this service uses adapters
 if (array_key_exists('adapter', $container)) {
 $config = (array) $container['adapter'];
 if (!isset($config['class'])) {
 throw new Exception("An adapter class must be set in $service service");
 }
 // Grab adapter name and remove unwanted the keys
 $adapter = $config['class'];
 unset($config['class'], $container['adapter']);
 // Create the instance and return it
 return new $class(new $adapter($config));
 }
 // Create class instance and pass parameters to constructor
 return new $class($container);
 }
}

Adding a new service must contain a name (id) and either a Closure object or an array. The following will create and return the same thing:

$container = new Container();
$container->add('session', function() {
 $config = array(
 'name' => 'my_session',
 'expires' => '4 hours',
 );
 $storage = new Session\Adapter\Native($config);
 return new Session($storage);
});
// - Equals to:
$container->add('session', array(
 'class' => 'Session',
 'adapter' => array(
 'class' => 'Session\Adapter\Native',
 'name' => 'my_session',
 'expires' => '4 hours',
 ),
));
// Now I get the shared object with:
$session = $container->get('session');
// Or create a new instance
$session = $container->getNew('session');

Am I doing it right?

asked Jun 30, 2011 at 7:01
\$\endgroup\$

3 Answers 3

6
\$\begingroup\$

Why are you defining the properties as static? I would absolutely not do that. It means two instantiations of the Container will have the same services.

answered Oct 7, 2011 at 20:38
\$\endgroup\$
3
\$\begingroup\$

I think that pimple ( http://pimple-project.org/ ) is the version used in symfony 2. might be worth checking out.

answered Aug 8, 2011 at 15:15
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nope, it's not used in Symfony2. It is used in Silex. And I agree with you, it's definitely a simple and good existing solution for the problem the OP is trying to solve. \$\endgroup\$ Commented Oct 7, 2011 at 20:39
1
\$\begingroup\$

You should read the following series of articles: http://fabien.potencier.org/article/11/what-is-dependency-injection

Additionally, the resulting component (PHP 5.2+) is there: http://components.symfony-project.org/dependency-injection/

answered Jun 30, 2011 at 9:16
\$\endgroup\$
1
  • \$\begingroup\$ The dependecy injection container from symfony is PHP 5.3+ \$\endgroup\$ Commented Nov 14, 2012 at 17:02

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.