Note
By the time I wrote my answer, you had changed your example from an interface implementation to a base class inheritance. My answer is still correct; since the LSP applies to interfaces and base classes as per this StackOverflow answer.
You did change more in the example than just inheritance/interface, which does influence the answer. I've addressed this at the bottom of this answer.
This is not a violation of the LSP.
It would be a violation if the method is wholly unusable, i.e. you're not supposed to ever call the method TagTransformer.transform.
Examples of the difference.
Excuse the C# syntax, it's been a while since I did PHP.
public interface ICalculation { void SetFirstNumber(int num); void SetSecondNumber(int num); int CalculateOutputFromNumbers(); }
Implementation 1:
public class Addition : ICalculation { public void SetFirstNumber(int num) { this.Number1 = num; } public void SetSecondNumber(int num) { this.Number2 = num; } public int CalculateOutputFromNumbers() { return this.Number1 + this.Number2; } }
This is clearly using the interface as intended. No issue here.
Implementation 2:
public class SquareRoot: ICalculation { public void SetFirstNumber(int num) { this.Number1 = num; } public void SetSecondNumber(int num) { throw new Exception("Square roots only take one input value!); } public int CalculateOutputFromNumbers() { return Math.Sqrt(this.Number1); } }
Notice how you're never going to be allowed to call the SetSecondNumber method from SquareRoot, even though the method is part of the ICalculation interface and SquareRoot implements ICalculation.
This violates LSP. In order to calculate a square root, SquareRoot class needs to be treated differently from other ICalculation-implementing classes.
Implementation 3:
public class Division : ICalculation { public void SetFirstNumber(int num) { this.Number1 = num; } public void SetSecondNumber(int num) { if(num == 0) throw new Exception("You can't divide by zero!"); this.Number2 = num; } public int CalculateOutputFromNumbers() { return this.Number1 / this.Number2; } }
Based on your question, it seems that you think this is a violation of LSP. This is essentially what's happening in your code example, a specific exception is being thrown for a given invalid value.
This is not a violation. Notice how you're allowed to call the SetSecondNumber method from Division, but you simply can't use an impossible value (0).
This isn't a matter of having to use the Division class differently from ICalculation-implementing classes; it's simply a matter of bad input, no possible output.
That is significantly different from the SquareRoot example; at least in relation to LSP.
In response to your new example
Your new example does in a way invalidate your original question.
Your old example was a PHP snippet:
public function transform($origin) { if (!is_string($origin)) throw new InvalidArgumentException(); ... }
It's important to note here that there is no type constraint on $origin. This means that checking for a usable type is a logical consequence, and not inherently bad design (since the language allows for untyped parameters).
However, this is significantly different in your revised example:
public function eat(Food $food) { if ($food instanceof Meat) throw new InvalidArgumentException(); ... }
It's important to note here that there is a type constraint on $food. You're no longer using a typeless parameter. You're specifying that the parameter is of type Food.
At this point, it becomes an LSP violation. Your input validation is no longer a matter of how the language works; but rather a consequence of the contract that is specified by your Animal base class.
You're trying to create a Cat which inherits from Animal but actually (partially) outright refuses to implement Eat(Food). That is a willful exclusion of functionality, which does make it an LSP violation.
I would consider this an LSP violation of Meat/Food, more than it is an LSP violation of Cat/Animal. Meat is clearly being treated differently from Food, which violates the contract that says that Meat is a Food.
eatortransformmethod in your post. Is throwing anInvalidArgumentExceptionan allowed action under the contract of the base class? If yes, it's not a violation, if no, it is a violation.