PHP LogoInterfaces and Abstract Classes

In object-oriented programming (OOP), interfaces and abstract classes are fundamental concepts for achieving abstraction, polymorphism, and defining contracts within a software system. While they both serve to define a blueprint that other classes must follow, they do so with distinct characteristics and use cases.

1. Interfaces

An interface defines a contract for the capabilities a class should have, specifying a set of method signatures that a class must implement. It's like a blueprint that declares "what a class can do" without providing any implementation details.

Key Characteristics of Interfaces:
* Contract Definition: Interfaces are purely about defining a contract. They declare method signatures (name, parameters, return type) but contain no method bodies (implementation).
* No Properties: Interfaces cannot contain properties (variables) of any kind. They can, however, define constants.
* Implicitly Public Methods: All methods declared in an interface are implicitly public. You cannot declare them with `private` or `protected` access modifiers.
* Multiple Inheritance of Type: A class can implement multiple interfaces, allowing it to inherit multiple sets of behaviors or capabilities. This is how PHP (and many other languages that don't support multiple class inheritance) achieves a form of multiple inheritance for behavior.
* Cannot be Instantiated: You cannot create an object directly from an interface. They exist solely to be implemented by concrete classes.
* Keyword: In PHP, interfaces are defined using the `interface` keyword and implemented using the `implements` keyword.

When to use Interfaces:
* When you need to define a contract for a specific behavior that might be shared across unrelated classes. For example, `LoggerInterface`, `Serializable`, `Drawable`.
* When you want to ensure that certain methods exist in different classes to achieve polymorphism, allowing you to treat objects of different classes uniformly if they implement the same interface.
* To achieve loose coupling in your design, promoting flexibility and testability.

2. Abstract Classes

An abstract class is a class that cannot be instantiated directly and may contain one or more abstract methods. It provides a common base for closely related classes, defining both common methods (with implementation) and methods that must be implemented by its concrete child classes.

Key Characteristics of Abstract Classes:
* Partial Implementation: Abstract classes can have both abstract methods (methods declared without an implementation, using the `abstract` keyword) and concrete methods (methods with full implementation).
* Can Have Properties: Abstract classes can define properties, just like regular classes.
* Access Modifiers: Abstract methods can have `public` or `protected` visibility. Concrete methods can have any visibility (`public`, `protected`, `private`).
* Single Inheritance: A class can only extend one abstract class. PHP, like many OOP languages, supports single inheritance for classes.
* Cannot be Instantiated: You cannot create an object directly from an abstract class. It must be extended by a concrete class, and that concrete class must implement all abstract methods defined in the abstract parent.
* Keyword: In PHP, abstract classes are defined using the `abstract class` keywords and extended using the `extends` keyword.

When to use Abstract Classes:
* When you want to provide a common base for a group of closely related classes, sharing some implementation details and enforcing others.
* When you have methods that make sense only in the context of the abstract class (e.g., `calculatePayroll()` in an `Employee` abstract class), but the exact implementation varies for different types of employees (e.g., `SalariedEmployee`, `HourlyEmployee`).
* To provide a default implementation for some methods while leaving others for subclasses to define.
* When you need to define common properties for a hierarchy of classes.

Similarities between Interfaces and Abstract Classes:
* Both cannot be instantiated directly.
* Both enforce method implementation in their child (concrete) classes.
* Both promote abstraction and polymorphism.

Differences between Interfaces and Abstract Classes:
* Implementation: Interfaces define *what* a class should do (no implementation). Abstract classes define *what* a class is and *how* some parts of it behave (can have partial implementation).
* Properties: Interfaces cannot have properties (variables), only constants. Abstract classes can have properties.
* Access Modifiers: Interface methods are implicitly public. Abstract methods can be public or protected.
* Inheritance: A class can `implement` multiple interfaces. A class can `extend` only one abstract class.
* Constructor: Interfaces cannot have constructors. Abstract classes can have constructors.

Example Code

<?php

// --- Interface Example: Defines a contract for drawable objects ---
interface Drawable {
    public function draw(): string; // Methods in an interface are implicitly public and abstract
}

// --- Abstract Class Example: Provides a common base for geometric shapes ---
abstract class GeometricShape {
    protected string $color;

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

    // Abstract method: Must be implemented by any concrete child class.
    // It defines a behavior without providing an implementation.
    abstract public function getArea(): float;

    // Concrete method: Provides a default implementation that child classes can use or override.
    public function getColor(): string {
        return $this->color;
    }

    // Another abstract method for demonstration
    abstract public function getName(): string;
}

// --- Concrete Class: Circle extends an abstract class and implements an interface ---
class Circle extends GeometricShape implements Drawable {
    private float $radius;

    public function __construct(string $color, float $radius) {
        parent::__construct($color); // Call the parent abstract class's constructor
        $this->radius = $radius;
    }

    // Implementation of the abstract method from GeometricShape
    public function getArea(): float {
        return M_PI * $this->radius * $this->radius;
    }

    // Implementation of the method from Drawable interface
    public function draw(): string {
        return "Drawing a {$this->color} circle with radius {$this->radius}.";
    }

    // Implementation of the abstract method from GeometricShape
    public function getName(): string {
        return "Circle";
    }
}

// --- Another Concrete Class: Rectangle extends an abstract class and implements an interface ---
class Rectangle extends GeometricShape implements Drawable {
    private float $width;
    private float $height;

    public function __construct(string $color, float $width, float $height) {
        parent::__construct($color);
        $this->width = $width;
        $this->height = $height;
    }

    // Implementation of the abstract method from GeometricShape
    public function getArea(): float {
        return $this->width * $this->height;
    }

    // Implementation of the method from Drawable interface
    public function draw(): string {
        return "Drawing a {$this->color} rectangle with width {$this->width} and height {$this->height}.";
    }

    // Implementation of the abstract method from GeometricShape
    public function getName(): string {
        return "Rectangle";
    }
}

// --- Usage Examples ---

// Create instances of concrete classes
$circle = new Circle("red", 5);
$rectangle = new Rectangle("blue", 4, 6);

echo "--- Circle Information ---\n";
echo "Name: " . $circle->getName() . "\n";
echo "Color: " . $circle->getColor() . "\n";
echo "Area: " . $circle->getArea() . "\n";
echo $circle->draw() . "\n\n";

echo "--- Rectangle Information ---\n";
echo "Name: " . $rectangle->getName() . "\n";
echo "Color: " . $rectangle->getColor() . "\n";
echo "Area: " . $rectangle->getArea() . "\n";
echo $rectangle->draw() . "\n\n";

// Demonstrate polymorphism with the interface
// We can put any object that implements 'Drawable' into this array
$drawables = [];
$drawables[] = $circle;
$drawables[] = $rectangle;

echo "--- Drawing all drawable objects ---\n";
foreach ($drawables as $drawable) {
    if ($drawable instanceof Drawable) {
        echo $drawable->draw() . "\n";
    }
}

// Demonstrate polymorphism with the abstract class
// We can put any object that extends 'GeometricShape' into this array
$shapes = [];
$shapes[] = $circle;
$shapes[] = $rectangle;

echo "\n--- Calculating areas of all geometric shapes ---\n";
foreach ($shapes as $shape) {
    if ($shape instanceof GeometricShape) {
        echo "The " . $shape->getName() . " (Color: " . $shape->getColor() . ") has an area of: " . $shape->getArea() . "\n";
    }
}

?>