DEV Community

Cover image for Exploring Late Static Binding in PHP
Al Amin
Al Amin

Posted on

Exploring Late Static Binding in PHP

๐Ÿง  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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 โœ…
Enter fullscreen mode Exit fullscreen mode
  • new static() โ†’ respects the child class
  • new self() โ†’ would have returned Animal in 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ Try replacing whatโ€™s needed:

class BaseController {
    public static function load() {
        echo "Creating " . ???;
        return ???;
    }
}

class UserController extends BaseController {}

$ctrl = UserController::load();
Enter fullscreen mode Exit fullscreen mode

(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)