Interface or an Abstract Class: which one to use?

An interface defines a set of methods that a class must implement, but does not provide any implementation for those methods. An abstract class, on the other hand, can provide some implementation for its methods, in addition to defining methods that derived classes must implement.

In general, use an interface when you want to specify a contract for a class to implement, but you don't want to provide any implementation. Use an abstract class when you want to provide a common implementation for some methods, but still want to allow derived classes to add their own unique behavior.

In PHP, abstract class and interface both can have constants, properties and methods but abstract class can have a constructor and an interface can not.

Here's an example:

<?php

interface Shape
{
  public function getArea(): float;
}

abstract class AbstractShape implements Shape
{
  protected float $width;
  protected float $height;

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

  abstract public function getArea(): float;
}

class Rectangle extends AbstractShape
{
  public function __construct(float $width, float $height)
  {
    parent::__construct($width, $height);
  }

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

class Triangle extends AbstractShape
{
  public function __construct(float $width, float $height)
  {
    parent::__construct($width, $height);
  }

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

$rectangle = new Rectangle(5, 10);
$triangle = new Triangle(5, 10);

echo "The area of the rectangle is: " . $rectangle->getArea() . "\n";
echo "The area of the triangle is: " . $triangle->getArea() . "\n";

In this example, the Shape interface defines a contract for classes that represent shapes, with a single method getArea() that returns the area of the shape. The AbstractShape class provides a common implementation for the width and height of a shape, as well as a default implementation of getArea() that calls an abstract method. The Rectangle and Triangle classes both extend the AbstractShape class and provide their own implementation of getArea().