Class must depend on abstractions not on concretions. More specifically, a class (high level module) must not depend on concretions (low level module), instead it should depend on abstractions. In other words, high level modules should never change and should be decoupled from low level modules that could change at any time.


# VIOLATION
class Publisher
{
private $twitter;

public function __construct(Twitter $twitter)
{
$this->twitter = $twitter;
}

public function publish()
{
return $this->twitter->getComment();
}
}

class Twitter
{
private $comment;

public function setComment(string $comment)
{
$this->comment = $comment;
}

public function getComment(): string
{
return $this->comment;
}
}

$twitter = new Twitter();
$twitter->setComment('Twitter comment');

$publisher = new Publisher($twitter);
echo $publisher->publish();

As you can see above, our Publisher (high level module) depends on Twitter (low level module) object because it is tightly coupled to it. It only accepts Twitter object. If we are to publish Facebook comments, we will end up modifying Publisher class which causes the violation. If we are to change Twitter class, we would potentially modify Publisher class which causes violation as well.


# REFACTORED
class Publisher
{
private $socialMedia;

public function __construct(SocialMediaInterface $socialMedia)
{
$this->socialMedia = $socialMedia;
}

public function publish()
{
return $this->socialMedia->getComment();
}
}

interface SocialMediaInterface
{
public function setComment(string $comment);
public function getComment(): string;
}

class Twitter implements SocialMediaInterface
{
private $comment;

public function setComment(string $comment)
{
$this->comment = $comment;
}

public function getComment(): string
{
return $this->comment;
}
}

class Facebook implements SocialMediaInterface
{
private $comment;

public function setComment(string $comment)
{
$this->comment = $comment;
}

public function getComment(): string
{
return $this->comment;
}
}

$twitter = new Twitter();
$twitter->setComment('Twitter comment');

$publisher = new Publisher($twitter);
echo $publisher->publish();

$facebook = new Facebook();
$facebook->setComment('Facebook comment');

$publisher = new Publisher($facebook);
echo $publisher->publish();

As you can see above, we have created SocialMediaInterface to let Twitter and Facebook classes to implement it. We now can safely inject both objects to Publisher class without breaking the functionality. If we create more social media classes to publish comment, all we have to do is, let our new class implement SocialMediaInterface.