What are the best practices for utilizing OOP principles in PHP, specifically in terms of class inheritance and relationships?

When utilizing OOP principles in PHP, it is important to properly structure class inheritance and relationships to ensure code reusability and maintainability. To achieve this, it is recommended to use abstract classes and interfaces to define common behavior and enforce contracts, and to favor composition over inheritance when possible.

// Example of utilizing class inheritance and relationships in PHP

// Abstract class defining common behavior
abstract class Shape {
    abstract public function getArea();
}

// Concrete classes inheriting from Shape
class Circle extends Shape {
    private $radius;

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

    public function getArea() {
        return pi() * pow($this->radius, 2);
    }
}

class Rectangle extends Shape {
    private $width;
    private $height;

    public function __construct($width, $height) {
        $this->width = $width;
        $this->height = $height;
    }

    public function getArea() {
        return $this->width * $this->height;
    }
}

// Interface defining contract for classes
interface Printable {
    public function printInfo();
}

// Class implementing Printable interface
class PrintableShape extends Shape implements Printable {
    public function printInfo() {
        echo "Area: " . $this->getArea();
    }
}

// Usage example
$circle = new Circle(5);
$rectangle = new Rectangle(4, 6);

$shapes = [$circle, $rectangle];

foreach ($shapes as $shape) {
    if ($shape instanceof Printable) {
        $shape->printInfo();
    }
}