Traits and Abstract Classes
Traits — reusable method sets
trait Loggable {n public function log(string $message): void {n echo "[" . static::class . "] $messagen";n }n}nnclass Course {n use Loggable;n}nn$course = new Course();n$course->log("Created"); // [Course] Created
PHP classes can only extends one parent, but they can use multiple traits at once. A trait shares real method implementations across otherwise unrelated classes without forcing them into a shared parent class — useful when several unrelated classes need the exact same small piece of behavior, like logging, without an artificial inheritance relationship between them.
Abstract classes
abstract class Notifier {n abstract public function send(string $message): void;nn public function announce(string $message): void {n $this->send("[Tutoline] $message");n }n}nnclass EmailNotifier extends Notifier {n public function send(string $message): void {n echo "Emailing: $messagen";n }n}
An abstract class can’t be instantiated directly with new — it defines a contract that subclasses must fill in (send), while still sharing common, already-implemented logic like announce() above. This mirrors exactly the same pattern you would find in Java’s abstract classes.
Interfaces, briefly
interface Cacheable {n public function getCacheKey(): string;n}nnclass Course implements Cacheable {n public function getCacheKey(): string {n return "course_" . $this->title;n }n}
Where an abstract class can share real implementation, an interface defines only the method signatures a class promises to provide, with zero implementation of its own — the same distinction covered in the Java course. A PHP class can implements multiple interfaces at once, even though it can only extends one class.