@nolros
ServiceProviders are bootstrapping your application, ie. they create required connections, bindings etc so you can do this:
$foo = App::make('Namespace\FooInterface');
somewhere in your code and let IoC Container take care of the implementation (let it be MysqlFoo or MongoFoo, PaypalBilling or StripeBilling etc). With this in place you need only to change one binding (in a service provider or wherever you did that) whenever you change implementation (use different package to do some job etc):
App::bind('Namespace\FooInterface', 'Namespace\MySql\Foo`);
// to
App::bind('Namespace\FooInterface', 'Namespace\Mongo\Foo`);
instead of editing your whole codebase and replacing 'manually' all occurences of:
$foo = new Namespace\MySql\Foo;
// to
$foo = new Namespace\Mongo\Foo;
Of course this is just a sensible example of their job, SP often do more work than just binding to IoC.
Next, you can have multiple level inheritance of course. Prototype and Factory are similar patterns, you can use one or the other, depending on your needs and liking. There's never one and only, right way of doing anything in programming, and that's the beauty of it. So whenever someone tells you you must use pattern X here or you should do this, because I tell you. in terms of design, you may want to discuss it with someone else to form your opinion.
Anyway, while DbRepo and CacheRepo could be substitutes in some cases, I wouldn't consider FileRepo the same, so I think that your example does too much.
Like above, there's no right way, but you definitely want your code to be SOLID, because it makes it soo much easier to work with. These are basic principles everyone should understand for their own good (and their coworkers too).
Oh, and btw, another thing: constructor is supposed to do just one thing in mot cases - accept dependencies. If you stick to it, then your code will be much more consistent, and you can use IoC goodness too.
IoC won't instantiate an object with construtor like this:
// $bar & $baz are scalar types (number / string / bool)
public function __construct(FooInterface $foo, $bar, $baz) {..}
Only immutable instances (for example value objects) should (and must) accept config in the constructor, because of their immutability:
$fixedArray = new SplFixedArray(10);
SplFixedArray is 'real' array type in PHP, while simple array is a bit of misconception - it's a mix for developer's convenience.