You know the situation: there's a class in your application that is presently carrying one or more methods that you'd like your new class to have access to. You know that duplicating code is a bad wrong thing because you're a subscriber to the Don't Repeat Yourself (DRY) principle. As a result, you can choose to do one of two things.

First mistake: Your new class extends the other class and bingo, now you've got easy access to that method that you so desire. You also have the other, irrelevant methods in your new class now too but that's ok, you've got the method that you want available with a call to $this->usefulMethod(). Ouch!

class OtherClass
{
   ...

   public function someUsefulMethod()
   {
       ... 
   }
}

class MyNewClass extends OtherClass
{
    // By the magic of inheritance, someUsefulMethod() is now available here too. 
}

Second mistake: Alternatively, you know that this would would be bad and wrong so you create a common base class, move the desired method into that one and have both the old and the new class extend the new common base. That is, assuming the old class isn't already extending a different class altogether. But this is bad and wrong too!

class UsefulAbstract
{
    public function someUsefulMethod()
    {
        ...
    }
}

class OtherClass extends UsefulAbstract
{
}

class MyNewClass extends UsefulAbstract
{
}

This looks ok. Your new class is no longer carrying around a ton of non-useful methods from OtherClass like it would have been doing in the first case. But, it's still bad and wrong.

You see, it all comes down to how you view abstraction and inheritance. When you adopt the mindset that a parent class is there to promote reusability of the methods that it exposes, you're much more likely to forget about maintaining type-safety.

What does this mean? When you use the extends keyword, you don't just have a parent class. You have a parent class that exposes an interface to the rest of the application. If the application's all working hunky-dorey before you extend a class, there's every chance that at least some of your application's code is working with the interface that the parent exposes.

If you then derive a child class from it, you have a tacit responsibility to maintain that interface in the child class. In other words, your child class should honour the parent's interface specification in order to remain compatible with any client code that engages with it.

The trouble is, when you create a parent class just for stashing convenience methods into, you're generally not even thinking about retaining type safety.

It's unlikely that you're thinking about the tight coupling that you've just hard coded into your application as well. Tight coupling? Hard coded dependency? What are you on about, I hear you ask.

Tight coupling is normally presented like this

class Car
{
    private $engine;

    public function __construct()
    {
        $this->engine = new Engine();
    }
}

Hard coded into the Car class is a dependency on the Engine class. The Car class as it's written cannot exist inside an application without the corresponding Engine class. Consequently, the Car and the Engine classes are said to be tightly coupled together. This is generally considered a bad thing. To fix the example above, you would inject the dependency as a method parameter, like so

class Car
{
    private $engine;

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

Now the Car class is no longer depending upon a very specific Engine class. Instead, as long as it gets an object that supports the EngineAbstract interface, it's happy and doesn't care one jot what the actual class name of the $engine parameter is. With the $engine being injected, the Car no longer has a hard coded dependency.

But how does this apply to inheritance?

Consider the class declaration for the child class.

class MyNewClass extends UsefulAbstract
{
    ...
}

The hard coded dependency is written right in there with extends UsefulAbstract. The problem that occurs here is not so much MyNewClass can't exist without UsefulAbstract also being present, although that still remains true of course.

No, the key problem that arises when you use inheritance as a mechanism for code reuse is that any and all of the child classes that you create from such a convenience oriented parent silently depend upon the parent's super useful method(s) never changing their interface specification.

Consider what would happen if the UsefulAbstract became so useful that you had loads of child classes derived from it. What would the impact be if you modified the return type of someUsefulMethod() in the parent? Will you change every place in your code base where the return value is handled? What if you miss one? What if you ended up "fixing this bit here but breaking that bit there". How do you accomodate that? Would you have some of the child classes override someUsefulMethod() so that it can call parent::someUsefulMethod() and then remangle the result?

That road leads to a spaghetti oriented nightmare of maintenance and bug-fixing.

Code reuse is good. Achieving it with inheritance is not just bad, it's super bad.

Instead, consider taking the logic of someUsefulMethod() and encapsulating it into an object of its own. That way, any objects that require its super usefulness can consume it either by retrieving it from a factory or dependency injection container. Or better still, if your new class really needs that utility method to function, the utility object can be injected into it either on the constructor or via a dedicated setter.

Just like the Car's $engine.

CAVEAT

If you've ever come into contact with one of the many MVC-like PHP frameworks out there in open source land (That's probably everyone then), there's a good chance that you've witnessed the exact technique that I seem to be railing against here. You know what I mean. The issue when a framework asks you to create your application's model classes by extending the framework's base model.

This is precisely the circumstance that I've labelled both as mistake #1 and mistake #2 up above.

How can I possibly be making such a claim when these frameworks are used by thousands upon thousands of developers. Well, take a peek under the hood. Is that base model class loaded with utility methods? Are they not God Objects? Do they not violate at least one of the five SOLID principles in one form or another? Usually, the Single Responsibility Principle is the first one to be tossed out of the window.

The benefits to using a framework are numerous of course: not reinventing the wheel, speed of development, promoting consistent coding approaches to creating the entities in your application and how they interact with each other.

Additionally, the responsibility for keeping the interfaces of those base classes consistent is not a burden that you have to shoulder. Generally, they have lots of developers curating the code base, and as such you can be reasonably confident that when an upgrade comes out, they won't have destroyed backwards compatibility and broken your application.

Only reasonably confident, mind.

The point to this caveat then is this: Just because the frameworks keep repeating the same bad programming practices over and over, it doesn't mean that you have to emulate them. Let them carry on doing their own thing, whilst you...

You are going to write proper code, with best practices in mind. Use composition (or traits!) for code reuse, not inheritance. And live a long and happy life with much less bug-fixing in your future.