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)