๐ง 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)