Introducing Bucket: A Minimal Dependency Injection Container for PHP

I got fed up with the lack of a decent DI-container for PHP, so today I created Bucket. To be clear, what I think is wrong with the currently available containers (at least that I’m aware of) is that they either are unstable, abandoned, require a lot of up-front configuration in external XML-files, or are tightly integrated into some full-stack framework. I had my hopes up for Phemto for a while, but it seems that progress has stalled.

Bucket doesn’t do much, but that is actually the intention. It means that it is feature-complete and probably bug free. And unlike Twittee, it is actually useful as-is.

Bucket is mostly a wrap-up of the code I described a bout a year back in Dealing with Dependencies. It adds a few additional features out-of-the-box. Notably:

Default factory uses reflection/typehints to determine dependencies. So you can go:

class Foo {
}
class Bar {
  function __construct(Foo $foo) {}
}
$container = new bucket_Container();
$container->get('Bar');

And with interfaces:

interface Zap {
}
class Foo implements Zap {
}
class Bar {
  function __construct(Zap $zap) {}
}
$container = new bucket_Container();
$container->registerImplementation('Zap', 'Foo');
$container->get('Bar');

You can use callbacks for factories. Not that useful right now, but when PHP 5.3 (hopefully very soon) sees the light of day, you can use:

$bucket = new bucket_Container(
  array(
    'pdo' => function($container) {
      return new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
    }
  )
);

You can also use a class based factory. This can be combined with callbacks, for overriding methods. Eg. if you create a callback, it takes precedence over the class method. Until 5.3, you’d probably want to write factories as class methods:

class MyFactory {
  function new_pdo($container) {
    return new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
  }
}
$bucket = new bucket_Container(new MyFactory());

Support for child scopes. Means that you can create a local container that doesn’t leak state to its parent. Probably not the most important feature for standard web applications, but a nice feature for longer running scripts. Usage is:

$container = new bucket_Container();
$scope = $container->makeChildContainer();

It’s just 153 lines of code, with no external requirements, so go on and grab your copy at: http://github.com/troelskn/bucket/tree/master

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Joshua May

    So, I take it when you were at fabpot’s github, you completely missed his “real” DI container? See: http://github.com/fabpot/dependency-injection/tree/master

    It’s none of the things you’re worried about – it’s completely decoupled from a framework (by design, though it shares symfony’s name), it’s stable, it’s maintained, and it’s super easy to configure (YAML is love!)

    Have a bit more of a read about it here: http://fabien.potencier.org/article/13/introduction-to-the-symfony-service-container

    Unless I’m missing something, I think it’s pretty much ideal.

  • Troels Knak-Nielsen

    @Joshua
    I admit I only looked at the documentation for it. Maybe I should give it another go. The YAML/XML configuration scared me away, as well as the sf prefix on the classes.
    Pake also used to be decoupled from Symfony, but is now tightly integrated into it. That makes me a bit suspicious, although it might just be me being paranoid.

  • Paul Annesley

    Josh: yeah, stick it to him. How dare somebody write a lightweight library that suits their needs and then publish it for the world to share. Without even first scouring the internet to find something they can bend into shape. The nerve *tuts*

  • Anonymous

    @Paul: I didn’t mean it like that at all.

    If there’s something that’s a “real” product, under active development that people can use, it’d be worth mentioning in the tutorial itself – that way people won’t be stuck with Bucket (assuming, of course, that its lifespan is roughly only as long as the tutorial itself)

    I’ve got no real problem that the tutorial has a lightweight implementation though, you know?

    Or, seemingly more on your level, “how dare I suggest that there’s another tool for the job – sharing knowledge about products and tools should be outlawed!”

  • kira8080

    The problem might have been the tone you used to suggest it.

  • Troels Knak-Nielsen

    Honestly, I didn’t take any offence from the first comment by Joshua. The web is full of libraries and frameworks and so it’s hard to be an expert in all of them before making a choice. I might have been too quick to write off sfServiceContainer; I’ll definitely take a second look.

    If there’s something that’s a “real” product, under active development that people can use, it’d be worth mentioning in the tutorial itself – that way people won’t be stuck with Bucket

    I think it’s feature complete – There’s nothing more to add to it. That doesn’t mean that you’re stuck in any way, since you can add whatever complicated factory you want on the backend. In the slightly larger perspective, DI-containers have the very fortunate attribute to them that they are easy to replace. By definition, the application level code has no knowledge about the container, so the only coupling there is, is in the configuration.

  • Mark

    I must also agree with Joshua! The symfony di container is all I have been using in my projects with perfect success. Make you finish reading all of fabpots articles to see the full system actually come together.