Composition vs. Inheritance in PHP: Why Composition is Better for Your Code

Harish Kumar · · 702 Views
Composition vs. Inheritance in PHP: Why Composition is Better for Your Code

In object-oriented programming, polymorphism can be achieved through two primary approaches: Inheritance and Composition. Let’s dive into their definitions and explore why composition is often the better choice.

Inheritance: The "Is-a" Relationship

Inheritance allows a class to derive behavior and properties from another class, creating an "is-a" relationship. For instance, "A dog is an animal" implies that the Dog class inherits from the Animal class. Here’s an example:

class Animal {
    public function makeSound() {
        echo "This animal makes a sound.";
    }
}

class Dog extends Animal {
    public function bark() {
        echo "This dog is barking.";
    }
}

$dog = new Dog();
$dog->makeSound(); // Output: This animal makes a sound.
$dog->bark();      // Output: This dog is barking.

While inheritance simplifies code reuse, it introduces tight coupling between the parent and child classes, making future modifications riskier.

Composition: The "Has-a" Relationship

Composition, on the other hand, enables a class to contain instances of other classes, forming a "has-a" relationship. For example, "A car has an engine." Here’s how this works:

class Engine {
    public function start() {
        echo "Engine is starting.";
    }
}

class Car {
    private $engine;

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

    public function drive() {
        $this->engine->start();
        echo " Car is driving.";
    }
}

$engine = new Engine();
$car = new Car($engine);
$car->drive(); // Output: Engine is starting. Car is driving.

Composition vs. Inheritance

Feature

Composition

Inheritance

Relationship

"Has-a" 

"Is-a"

Coupling

Loosely coupled 

Tightly coupled

Flexibility

High; you can swap or replace components 

Low; changes in the parent affect child

Reuse

Reuses behavior via delegation 

Reuses behavior via extension

By using composition, classes remain modular and adaptable to change. Let’s explore the advantages of composition in greater detail.

1. Maintainability and Loose Coupling

Consider this inheritance-based example:

class Logger {
    public function log($message) {
        echo "Log: $message";
    }
}

class FileLogger extends Logger {
    public function writeToFile($message) {
        $this->log($message);
        echo " Writing log to file.";
    }
}

$fileLogger = new FileLogger();
$fileLogger->writeToFile("System started");
// Output: Log: System started Writing log to file.

In this case, changes to the Logger class may break the FileLogger class, creating tight coupling. Now, let’s rewrite it using composition:

class Logger {
    public function log($message) {
        echo "Log: $message";
    }
}

class FileLogger {
    private $logger;

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

    public function writeToFile($message) {
        $this->logger->log($message);
        echo " Writing log to file.";
    }
}

$logger = new Logger();
$fileLogger = new FileLogger($logger);
$fileLogger->writeToFile("System started");
// Output: Log: System started Writing log to file.

With composition, Logger and FileLogger are decoupled, reducing the risk of unintended side effects.

2. Better Testability

Composition makes it easier to mock dependencies for testing. Let’s look at an example:

class Mailer {
    public function send($message) {
        echo "Email sent: $message";
    }
}

class Notification {
    private $mailer;

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

    public function notify($message) {
        $this->mailer->send($message);
    }
}

// Mocking Mailer for testing
class MockMailer {
    public function send($message) {
        echo "Mock email sent: $message";
    }
}

$mockMailer = new MockMailer();
$notification = new Notification($mockMailer);
$notification->notify("Test notification");
// Output: Mock email sent: Test notification

Here, we replace the real Mailer class with a MockMailer class for testing purposes, ensuring the Notification class behaves as expected.

3. Overcoming the Lack of Multiple Inheritance

PHP doesn’t support multiple inheritance, but composition provides a workaround. Consider this example:

class SoundSystem {
    public function playMusic() {
        echo "Playing music.";
    }
}

class AirConditioner {
    public function setTemperature($temp) {
        echo "Setting temperature to $temp°C.";
    }
}

class Car {
    private $soundSystem;
    private $airConditioner;

    public function __construct(SoundSystem $soundSystem, AirConditioner $airConditioner) {
        $this->soundSystem = $soundSystem;
        $this->airConditioner = $airConditioner;
    }

    public function enjoyRide() {
        $this->soundSystem->playMusic();
        echo " ";
        $this->airConditioner->setTemperature(22);
    }
}

$soundSystem = new SoundSystem();
$airConditioner = new AirConditioner();
$car = new Car($soundSystem, $airConditioner);
$car->enjoyRide();
// Output: Playing music. Setting temperature to 22°C.

Here, the Car class combines functionality from both SoundSystem and AirConditioner without relying on inheritance.

Conclusion

While inheritance can simplify initial development, it often leads to tightly coupled and less flexible code. Composition, by contrast, promotes modularity, maintainability, and testability. By choosing composition over inheritance, you can build PHP applications that are robust, scalable, and easier to maintain.

.

🔥 Boost Your Productivity with Ctrl+Alt+Cheat!

Take your coding efficiency to the next level with Ctrl+Alt+Cheat, the ultimate VSCode extension for developers. Whether you're working with PHP, JavaScript, Laravel, or any other technology, this extension provides over 60 curated cheat sheets to speed up your workflow.

Special Offer: Use the discount code "YT-FAMILY" at checkout and get an exclusive 50% discount. Don't miss this chance to supercharge your development experience—grab Ctrl+Alt+Cheat today!

👉 Download Ctrl+Alt+Cheat today and start coding like a pro!

0

Please login or create new account to add your comment.

0 comments
You may also like:

Understanding PHP Invokable Classes: Examples, Use Cases, and Real-World Applications

In PHP, an invokable class is a class you can call like a function. To make a class invokable, PHP provides a special magic method called __invoke(). Once implemented, this allows (...)
Harish Kumar

What is PSR-6? A Beginner’s Guide to PHP Caching Standards

Is your PHP application slowing down because of repeated database queries or inefficient caching? Do you wish switching between caching libraries was simpler? That’s where PSR-6 (...)
Harish Kumar

Exploring Asymmetric Property Visibility in PHP 8.4

The release of PHP 8.4 introduces a powerful new feature: Asymmetric Property Visibility, enabling developers to define separate visibility rules for reading and writing properties. (...)
Harish Kumar

What's New in PHP 8.4: Key Enhancements and Updates

As PHP 8.4's release on November 21, 2024, approaches, it's clear that PHP continues to evolve and delight its developer community. For those who have been coding with PHP since (...)
Harish Kumar

Introducing Tools to Supercharge PHP-FPM Efficiency and Monitoring

PHP-FPM stands for PHP FastCGI Process Manager. It’s an improved way to manage PHP processes that makes web applications faster and more efficient. Instead of running each PHP (...)
Harish Kumar

PHP 8.4 Property Hooks: The Ultimate Guide for Developers

PHP 8.4, coming in November 2024, introduces a new feature called property hooks. This feature makes it easier to work with class properties by allowing you to define custom behavior (...)
Harish Kumar