Advanced OOP: Encapsulation, Inheritance, Interfaces & Traits
Study Deep: Late Static Binding (static::)
In PHP, the self:: keyword always refers to the class where it is written. However, the static:: keyword (Late Static Binding) refers to the class that was actually called at runtime.
Example:
class ParentClass {
public static function who() { echo "Parent"; }
public static function test() { static::who(); } // Uses Late Static Binding
}
class ChildClass extends ParentClass {
public static function who() { echo "Child"; }
}
ChildClass::test(); // Output: Child (If using self::, output would be Parent)
1. Encapsulation & Access Modifiers
Definition: Encapsulation is the OOP principle of bundling data (properties) and the methods that operate on that data together inside a class, while restricting direct access from outside using access modifiers. It is the programming equivalent of a capsule — keeping the internals hidden and safe.
The Three Access Modifiers:
| Modifier | Accessible Inside Class | Accessible in Child Class | Accessible Outside Class |
|---|---|---|---|
public | ✓ Yes | ✓ Yes | ✓ Yes |
protected | ✓ Yes | ✓ Yes | ✗ No |
private | ✓ Yes | ✗ No | ✗ No |
Best Practice — Getters and Setters: Declare properties as private and provide public get and set methods to control access. This allows you to add validation logic.
class Person {
private $age; // Direct access blocked from outside
// Setter — includes validation
public function setAge($age) {
if ($age < 0 || $age > 150) {
echo "Invalid age!";
} else {
$this->age = $age;
}
}
// Getter
public function getAge() {
return $this->age;
}
}
$p = new Person();
$p->setAge(25);
echo $p->getAge(); // Output: 25
$p->setAge(-5); // Output: Invalid age!
// $p->age = 30; // FATAL ERROR: Cannot access private property
2. Inheritance
Definition: Inheritance is an OOP mechanism that allows a child class (subclass) to automatically acquire all public and protected properties and methods from a parent class (superclass), using the extends keyword. It promotes code reuse and establishes an "is-a" relationship.
Syntax: class ChildClass extends ParentClass { }
// Parent Class
class Animal {
public $name;
public function __construct($name) {
$this->name = $name;
}
public function eat() {
echo "{$this->name} is eating.<br>";
}
public function breathe() {
echo "{$this->name} is breathing.<br>";
}
}
// Child Class — Dog inherits from Animal
class Dog extends Animal {
public function bark() {
echo "{$this->name} says: Woof! Woof!<br>";
}
}
// Child Class — Cat inherits from Animal
class Cat extends Animal {
public function meow() {
echo "{$this->name} says: Meow!<br>";
}
}
$dog = new Dog("Rex");
$dog->eat(); // Inherited from Animal
$dog->bark(); // Own method
$cat = new Cat("Bella");
$cat->breathe(); // Inherited from Animal
$cat->meow(); // Own method
3. Method Overriding
Definition: A child class can redefine (override) a method inherited from the parent class to provide its own specific implementation. The parent's version is replaced when the method is called on a child object. Use parent::methodName() to call the parent's version from inside the child.
class Shape {
public function area() {
echo "Calculating area of generic shape.<br>";
}
}
class Circle extends Shape {
private $radius;
public function __construct($r) { $this->radius = $r; }
// Override parent's area() method
public function area() {
$a = 3.14159 * $this->radius ** 2;
echo "Circle area: $a<br>";
}
}
class Rectangle extends Shape {
private $w, $h;
public function __construct($w, $h) { $this->w=$w; $this->h=$h; }
public function area() {
echo "Rectangle area: " . ($this->w * $this->h) . "<br>";
}
}
$shapes = [new Circle(5), new Rectangle(4, 6)];
foreach ($shapes as $s) {
$s->area(); // Polymorphism: right area() is called for each type
}
4. Types of Inheritance in PHP
| Type | Description | PHP Support |
|---|---|---|
| Single | Class B extends Class A | ✓ Yes |
| Multilevel | Class C extends Class B, which extends Class A | ✓ Yes |
| Hierarchical | Class B and Class C both extend Class A | ✓ Yes |
| Multiple | Class C extends both Class A and Class B | ✗ Not Supported (use Interfaces or Traits instead) |
// Multilevel Inheritance Example
class Vehicle { public function move() { echo "Moving<br>"; } }
class Car extends Vehicle { public function drive() { echo "Driving<br>"; } }
class SportsCar extends Car { public function turbo() { echo "Turbo boost!<br>"; } }
$sc = new SportsCar();
$sc->move(); // From Vehicle
$sc->drive(); // From Car
$sc->turbo(); // Own method
5. The final Keyword
Definition: The final keyword prevents a class from being extended (inherited) or prevents a method from being overridden.
// Final class — cannot be inherited
final class Database {
public function connect() { echo "Connecting..."; }
}
// class MySQLDB extends Database {} // FATAL ERROR
// Final method — cannot be overridden
class Animal {
final public function breathe() { echo "Breathing..."; }
}
class Fish extends Animal {
// public function breathe() {} // FATAL ERROR — cannot override final method
}
6. Abstract Classes
Definition: An abstract class is a class that cannot be instantiated directly. It is designed to be a base class. It can contain abstract methods (methods with no body) that must be implemented by any concrete child class.
abstract class Shape {
abstract public function area(); // No implementation — child MUST define this
public function describe() { // Concrete method — shared by all children
echo "I am a shape. My area is: " . $this->area() . "<br>";
}
}
class Triangle extends Shape {
private $b, $h;
public function __construct($b, $h) { $this->b=$b; $this->h=$h; }
public function area() { // MUST implement abstract method
return 0.5 * $this->b * $this->h;
}
}
$t = new Triangle(6, 4);
$t->describe(); // I am a shape. My area is: 12
7. Interfaces
Definition: An Interface defines a contract — a set of method signatures that any class implementing it MUST provide. Unlike abstract classes, an interface cannot contain any implemented methods (only method declarations). A class can implement multiple interfaces, making interfaces PHP's solution to multiple inheritance.
Key Rules:
- All interface methods are implicitly
publicandabstract. - A class uses the
implementskeyword. - One class can
implementmultiple interfaces (comma-separated). - Interfaces CAN have constants.
| Feature | Interface | Abstract Class |
|---|---|---|
| Method bodies | ✗ Not allowed | ✓ Allowed (concrete methods) |
| Properties | Constants only | Yes (any visibility) |
| Multiple use | implements multiple | Can extend only ONE |
| Constructor | ✗ Cannot have one | ✓ Can have one |
| Use when | Defining a "can-do" contract | Sharing base behavior |
interface Printable {
public function printData(); // No body — just a contract
}
interface Saveable {
public function save($filename);
}
// A class can implement MULTIPLE interfaces
class Report implements Printable, Saveable {
private $data;
public function __construct($data) { $this->data = $data; }
public function printData() { // MUST implement
echo "Printing: {$this->data}<br>";
}
public function save($filename) { // MUST implement
file_put_contents($filename, $this->data);
echo "Saved to: $filename<br>";
}
}
$r = new Report("Student List");
$r->printData();
$r->save("students.txt");
// If a class implements an interface but doesn't define all its methods → FATAL ERROR
8. Traits
Definition: A Trait is a mechanism for horizontal code reuse that overcomes single-inheritance limitations. A trait is a set of methods that can be "mixed into" multiple classes using the use keyword — without requiring a shared parent class. Think of traits as "copy-paste of methods" at compile time.
trait Logger {
public function log($msg) {
echo "[LOG " . date("H:i:s") . "] $msg<br>";
}
}
trait Validator {
public function isNotEmpty($value) {
return !empty(trim($value));
}
}
class UserService {
use Logger, Validator; // Mix in BOTH traits
public function createUser($name) {
if ($this->isNotEmpty($name)) { // From Validator trait
$this->log("Creating user: $name"); // From Logger trait
echo "User '$name' created!<br>";
} else {
$this->log("Error: name is empty.");
}
}
}
class ProductService {
use Logger; // Reuse Logger in a completely different class
public function addProduct($item) {
$this->log("Adding product: $item");
echo "Product '$item' added!<br>";
}
}
$svc = new UserService();
$svc->createUser("Rohit"); // [LOG 14:32:10] Creating user: Rohit → User 'Rohit' created!
$svc->createUser(""); // [LOG 14:32:10] Error: name is empty.
Trait vs Interface vs Abstract Class:
| Trait | Interface | Abstract Class | |
|---|---|---|---|
| Can have method bodies | ✓ Yes | ✗ No | ✓ Yes (both concrete & abstract) |
| Multiple use per class | ✓ Yes (use T1, T2) | ✓ Yes (implements I1, I2) | ✗ Only one (extends) |
| Can be instantiated | ✗ No | ✗ No | ✗ No |
| Purpose | Code reuse without inheritance | Contract / specification | Partial base implementation |
9. Static Properties and Methods
Definition: A static property or method belongs to the class itself, not to any individual object. It is shared across all instances and can be accessed without creating an object using ClassName:: syntax.
Key Rules:
- Declared with the
statickeyword. - Accessed outside:
ClassName::$propertyorClassName::method(). - Inside the class:
self::$propertyorself::method(). - Static properties share a single value across all objects of the class.
class Counter {
public static $count = 0; // Single shared value across all objects
public function __construct() {
self::$count++; // Increment every time a new object is created
}
public static function getCount() { // Can be called without an object
return self::$count;
}
public static function reset() {
self::$count = 0;
}
}
$a = new Counter();
$b = new Counter();
$c = new Counter();
echo Counter::getCount(); // Output: 3 (no object needed!)
Counter::reset();
echo Counter::getCount(); // Output: 0
Practical Use — Singleton Pattern (only one DB connection allowed):
class Database {
private static $instance = null; // Store the single instance
private function __construct() { /* private: cannot use new Database() */ }
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new Database();
echo "New DB connection created.<br>";
}
return self::$instance;
}
}
$db1 = Database::getInstance(); // New DB connection created.
$db2 = Database::getInstance(); // No new connection — returns same instance
// $db1 === $db2 → true
| Aspect | Non-Static (Instance) | Static (Class) |
|---|---|---|
| Belongs to | A specific object | The class itself |
| Access syntax | $obj->method() | ClassName::method() |
| Inside class | $this->property | self::$property |
| Memory | New copy per object | Single shared copy |
| Requires object creation | Yes | No |
10. Magic Methods
Definition: Magic methods are special PHP methods that begin with double underscores (__). PHP automatically invokes them when certain actions are performed on objects — such as printing the object, accessing undefined properties, or invoking undefined methods.
| Magic Method | Triggered When |
|---|---|
__construct() | new ClassName() is called |
__destruct() | Object is destroyed or script ends |
__toString() | Object is used as a string (e.g., echo $obj) |
__get($name) | Reading an undefined / inaccessible property |
__set($name, $val) | Setting an undefined / inaccessible property |
__isset($name) | isset() or empty() called on inaccessible property |
__unset($name) | unset() called on inaccessible property |
__call($name, $args) | Calling an undefined method on an object |
__callStatic($n, $a) | Calling an undefined static method |
__clone() | Object is cloned with the clone keyword |
class MagicBox {
private $data = [];
// Intercept setting of undefined/private properties
public function __set($name, $value) {
$this->data[$name] = $value;
echo "Set '$name' = '$value'<br>";
}
// Intercept reading of undefined/private properties
public function __get($name) {
return $this->data[$name] ?? "Property '$name' not set";
}
// Intercept isset() on undefined/private properties
public function __isset($name) {
return isset($this->data[$name]);
}
// Called when object is used as a string
public function __toString() {
return "MagicBox [" . implode(", ", array_keys($this->data)) . "]";
}
// Called when undefined methods are invoked
public function __call($name, $args) {
echo "Method '$name' not found. Args: " . implode(", ", $args) . "<br>";
}
}
$box = new MagicBox();
$box->city = "Delhi"; // __set: Set 'city' = 'Delhi'
$box->country = "India"; // __set: Set 'country' = 'India'
echo $box->city . "<br>"; // __get: Delhi
echo $box->planet . "<br>"; // __get: Property 'planet' not set
echo $box . "<br>"; // __toString: MagicBox [city, country]
var_dump(isset($box->city)); // __isset: bool(true)
$box->fly("fast", "high"); // __call: Method 'fly' not found. Args: fast, high