Developers can leverage OOP (Object-oriented programming) to reuse code, but, in my experience, beginners tend to have difficulties in understanding when to use a specific pattern or a built-in PHP structure.
Business teams usually cannot afford to develop the same modules from scratch every time they need a new feature.
That's why dev teams use patterns and OOP principles to reduce the TTM (Time To Market) and bugs while keeping the code maintainable and extensible.
Code reuse is a craft, though, that requires experience and accuracy. There's no magic recipe you can apply blindly, but a few design principles can prevent very bad failures.
You won't be able to run on water, but, at least, you may avoid common traps.
Basic inheritance with the keyword
extends is one of the first tricks you'll learn as a beginner.
It's pretty straightforward: you have a mother class and child classes, perhaps childs for the child classes, and so on.
It may look fine at first sight. You define some methods and properties in the mother class, and child classes can override or reuse them.
Cool but quite limited, as modern apps usually require more sophisticated patterns, as not everything can be represented as a parent-child relationship.
Besides, it's easy to break the encapsulation by exposing the implementation (~ code integrity), which can lead to nasty bugs. On top of that, PHP does not support multiple inheritance like some other programming languages, so you'll have to stick with single inheritance.
Fortunately, there are other ways such as polymorphism to fix the problem, but even such approaches are not meant for every situation.
Traits allow reusing code, so you can share common methods between multiple classes that do not have the same purpose or behaviour. Using a PHP trait can be better than implementing an interface. But when?
Traits can help when the implementation is the same everywhere, and interfaces are meant for the exact opposite case. In other words, when the the methods share a common structure but their bodies differ, the interface makes sense.
We want to force classes to declare some methods, but the implementation is not our problem. Such polymorphic approach allows other parts of the code to use objects without knowing their implementation.
In contrast, if you have to re-implement the same interface over and over without modifying anything, you will only generate duplicates. Instead, you may use PHP Traits.
However, Traits are not perfect at all, and some PHP developers simply prefer not using them, as it's still possible to modify the visibility of the imported methods!
The idea with encapsulation is to protect objects and their properties by preventing unwanted modifications from external code.
That's why you only want to use the
public keyword in specific cases. Most of the time, methods and properties should stay private or protected.
The problem is that devs might be tempted to introduce setters to bypass this fundamental mechanism:
private int $id;
// don't use that, use a constructor instead
public function setId(int $id): int
$this->id = $id;
$id is declared as private, but the setter breaks its encapsulation, allowing anyone to change the ID at will.
In a nutshell, setters are not meant for code reuse.
You can clone objects to reuse them without affecting existing instances.
clone before the object you want to clone.
You can also define the magic method
clone() inside the associated class to fine tune the copy or forbid it.
An object called service is injected in another object called client. Services are dependencies.
Instead of hardcoding classes inside the client's constructor and instanciate them manually, we pass them directly as arguments:
public function __construct(
protected Service $service
Many PHP frameworks such as Symfony use similar approaches, but they usually add some magic to instanciate dependencies, so you don't have to handle it.
Behind the scene, there are containers and interfaces that have the necessary information to set your dependencies. You may find related terms such as "resolvers" or "autowire."
You may read PHP-DI to dig further.
We only saw a few tricks to reuse PHP code and some traps to avoid, but these ones are quite frequent.