I suppose explaining the problem it (may) provides a solution for.
Let's say you have a class which interacts at some level with several others. Now the number of classes that are required could be an arbitrary number. Typical approach is to require the classes, and instantiate them as needed. This could be by instantiating them outside the class, and them "injecting" them somehow (maybe the constructor or a init() method) or instantiating inside the class. In either case you have a small problem.
The class has developed a dependency on these classes, since it knows both their class names, requires them as paramaters, or suddenly has responsibility for instantiating them. On the face of it, the class works fine. Problem is dependencies will need to be carried forward for re-use or else the class will need future editing to enable changed dependencies. This is fine when talking about one class - now apply it across a few dozen. See the molehill turning into a mountain? There's also a testing dilemma - how to test a class which insists on instantiating external objects in defiance of our need to manipulate those same classes via stubs, mocks or some other alternative. The problem list grows, that mole is mutating.
The first solution, is to remove the instantiation from the class. Do it elsewhere and pass the dependencies into the object via the constructor. This solves the instantiation issue, but adds another. Who's going to remember our growing parameter list, it's order, etc. Will we need to do this for every instantiation? When we change the paramater list, will we have to edit all those instantiation lines across the application?
Remove one potential problem, and we find another.
This eventually leads us the quartet of possible solutions - we need to avoid:
a) instantiating objects inside the class (it can still be done, but our unit testing will become a nightmare)
b) passing a potentially changing list of parameters to all instantiation events
The quartet of possible solutions?
1. Singletons!
2. A Registry
3. ServiceLocator
4. Dependency Injection
Singletons can help avoid parameter lists - but it's merely replacing the in-class instantiation. We would need to add some extra wiring to facilitate testing, and well, singletons are a bit like Globals.
A Registry does away with a long parameter list, and it can jump the Singleton issue a little. Just register the dependencies to the Registry, and pass it into the class as a parameter (no more long hard to remember parameter list), or we can make the Registry a Singleton itself and call it from the class constructor with the parameter option left open to facilitate testing. This is the commonly used option...
A ServiceLocator does a similar job to the Registry, but in addition it takes control of finding, including, and finally instantiating classes. It can help reduce all those include calls littered everywhere in the code (and we all know they can wind up anywhere

).
Dependency Injection is another step up the ladder - and I have never seen a real PHP example outside a theoretical discussion.
To sum up the ramble (hoping it makes sense because I'm speed typing) - Registry/ServiceLocator try to solve the problem of getting dependencies into a class in such a way that it makes testing simple, avoids long parameter lists (hard to remember, easy to make mistakes with), narrows the dependencies by concealing (not always possible - but often) the class name so classes of varying types with the same interface are acceptable, lets developers worry about more important things and cuts down on maintenance due to dependency changes (edit one class, not every occurance of the "new" keyword!).
Someone else's turn to cut in now...