🧠 PHP Late Static Binding Explained: self:: vs static:: vs new static() for Real-World Use
Hey fellow devs,
Ever found yourself confused by the difference between self::, static::, new self() and new static() in PHP?
I did too. Until I slowed down, played with examples, and finally understood the beauty of something called Late Static Binding (LSB).
Let’s break it down like we’re talking over a project debug session.
🤔 What’s the Problem?
You have a parent class that defines a static method. You extend it with a child class and call the method from the child. But surprisingly, the method behaves like it’s still running in the parent.
Like this:
class ParentClass {
    public static function whoAmI() {
        echo "I am " . self::class;
    }
}
class ChildClass extends ParentClass {}
ChildClass::whoAmI(); // ❌ Output: I am ParentClass
Why did it say ParentClass? You called it from ChildClass, right?
Because self:: refers to the class where the method is defined, not who called it.
And that's the limitation Late Static Binding solves.
  
  
  🛠 Enter: static:: — the Fix
class ParentClass {
    public static function whoAmI() {
        echo "I am " . static::class;
    }
}
class ChildClass extends ParentClass {}
ChildClass::whoAmI(); // ✅ Output: I am ChildClass
That’s it! With static::, PHP waits until runtime to figure out which class is calling. Hence the term late binding.
  
  
  🧪 self::class vs static::class
| Keyword | What it returns | When it's resolved | 
|---|---|---|
| self::class | The class where it's written | At compile time | 
| static::class | The class that called it | At runtime ✅ | 
This is especially powerful in patterns like factories or service locators.
  
  
  🎭 Object Creation: new self() vs new static()
Let’s create objects and see the difference:
class Animal {
    public static function create() {
        return new static(); // 👈 creates the calling class
    }
}
class Dog extends Animal {}
class Cat extends Animal {}
$dog = Dog::create(); 
$cat = Cat::create();
echo get_class($dog); // Dog ✅
echo get_class($cat); // Cat ✅
- 
new static()→ respects the child class
- 
new self()→ would have returnedAnimalin both cases ❌
So again...
| Expression | What it does | 
|---|---|
| new self() | Create object of defined class | 
| new static() | Create object of calling class ✅ | 
🔌 Real Use Case (Like in a Plugin)
Imagine you're building a WordPress plugin with multiple shortcode handlers. You could create a BaseShortcode like this:
class BaseShortcode {
    public static function init() {
        echo "Booting: " . static::class . "\n";
        return new static(); // 🎯
    }
}
class GalleryShortcode extends BaseShortcode {}
class FormShortcode extends BaseShortcode {}
$g = GalleryShortcode::init(); // GalleryShortcode
$f = FormShortcode::init();    // FormShortcode
If you had used new self() and self::class, both would have printed BaseShortcode. Not what you want when building reusable code, right?
🧠 Think of It Like This
- 
self::/new self()→ fixed, bound to the class that wrote the method
- 
static::/new static()→ flexible, bound to the class that called the method
Late static binding gives your OOP code dynamic power while keeping it clean.
🧪 Practice Time
Can you make this code output:
Creating UserController
👉 Try replacing what’s needed:
class BaseController {
    public static function load() {
        echo "Creating " . ???;
        return ???;
    }
}
class UserController extends BaseController {}
$ctrl = UserController::load();
(Answer: replace ??? with static::class and new static() 😉)
🧵 Final Thoughts
Late static binding might sound fancy, but it's just a tool that lets your code act more like real-world behavior: flexible, extendable, and smart at runtime.
When you’re building reusable components, plugin frameworks, or Laravel-style factories — understanding this makes your OOP code next level.
 
 
              
 
    
Top comments (0)