Any method that takes class X as an argument must be able to work with any sub classes of X. In short terms, a subclass should be able override the parent class' methods without breaking functionality. Another way of describing it is, an object with a specific interface can be replaced by a different object with same interface without breaking the application's original behaviour.


# VIOLATION
interface SportsInterface
{
public function pass(string $ball);
public function tackle(string $opponent);
}

class Footballer implements SportsInterface
{
public function pass(string $ball)
{
// Passing the $ball
}

public function tackle(string $opponent)
{
// Tackling the $opponent
}
}

class English extends Footballer implements SportsInterface
{
public function pass(string $ball)
{
// I am able to pass the $ball
}

public function tackle(string $opponent)
{
// I am able to tackle the $opponent
}
}

class Spanish extends Footballer implements SportsInterface
{
public function pass(string $ball)
{
// I am able to pass the $ball
}

public function tackle(string $opponent)
{
throw new Exception('Sorry, I am too nice to tackle my opponents.');
}
}

In example above, we expect English and Spanish footballers to be able to pass the ball and tackle opponents as Footballer class dictates. However, the Spanish footballer doesn't seem to be able to tackle opponents. This is a violation because Footballer class dictates the tackle.


# VIOLATION
class Outputer
{
private $computer;

public function __construct(ComputerInterface $computer)
{
$this->computer = $computer;
}

public function output()
{
return implode(',', $this->computer->getData());
}
}

interface ComputerInterface
{
public function getData();
}

class Terminal implements ComputerInterface
{
protected $data;

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

public function getData()
{
return $this->data;
}
}

class Browser extends Terminal
{
public function __construct($data)
{
parent::__construct($data);
}

public function getData()
{
return json_encode($this->data);
}
}

# This would work
$terminal = new Terminal(['Hello', 'World']);
$outputer = new Outputer($terminal);
echo $outputer->output();

# This would fail
$browser = new Browser(['Hello', 'World']);
$outputer = new Outputer($browser);
echo $outputer->output();

This is another violation example. The reason why this is a violation is because the getData method of Browser subclass returns a JSON encoded string instead of an array like dictated in parent Terminal class. When we inject: