Dependency injection

The idea with "dependency injection" is to have replaceable components in your code. For example, if you write a method for registering a user and, after the registration is complete, you decide to send the user a message, then the part that sends the message should be a replaceable component, so that you can swap it at any time with something else (maybe now you want to send emails, maybe in the future you'll want to send SMS messages, or maybe you want to create unit tests in which you need to see what the method is trying to send, instead of actually sending).

To do that, you can employ the following simple technique:

class User {
    protected $messenger;

    public function getMessenger() {
        return $this->messenger;
    }

    public function setMessenger($messenger) {
        $this->messenger = $messenger;
    }

    public function register() {
        // ... registration code ...

        $messenger = $this->getMessenger();
        if (!empty($messenger)) {
            $messenger->sendMessage($recipient, $subject, $message);
        }
    }
}

Now, if you want to send email messages and you have an EmailMessenger class that can do the job, you have to specify the email messanger with the setMessenger() method. This can actually be the default, and the getMessenger() method could return a new instance of the EmailMessenger if it determines that you have not set any messenger.

$user = new User();
$user->setMessenger(new EmailMessenger());
$user->register();

Any time you want to switch to a different messenger, you simply specify it with the setMessenger() method.

$user->setMessenger(new SMSMessenger());

You also need to make sure that the object that gets passed to the setMessenger() method is always a messenger and it always has a sendMessage() method, otherwise the call in register() will break. A simple and unobtrusive way of doing that is to have an IMessenger interface that all messengers must implement.

interface IMessenger {
    public function sendMessage($recipient, $subject, $message);
}

For this to be effective, you will also need to enforce the use of such classes in the messenger setter.

public function setMessenger(IMessenger $messenger) {
    $this->messenger = $messenger;
}