← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Late Static Binding (static::)

php PHP 5.3+ Advanced
debt(d5/e1/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5): detection_hints lists phpstan and psalm as the tools that catch self:: used where static:: is intended. These are specialist static analysis tools, not default linters or the compiler — a developer must opt in to run them, matching the d5 anchor exactly.

e1 Effort Remediation debt — work required to fix once spotted

Closest to 'one-line patch or single-call swap' (e1): the quick_fix is explicit — replace self:: with static:: (or vice versa) at the affected call site. This is a single-keyword substitution, firmly at e1.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3): the choice is scoped to class hierarchies using static methods. It imposes a conceptual tax on maintainers working with OOP inheritance chains, but code outside those classes is entirely unaffected. Not wide enough for b5 but more than b1.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7): the misconception field states directly that developers believe self:: and static:: are interchangeable — a natural assumption because both appear to reference 'the current class'. The trap contradicts how self:: behaves in other OOP languages where the equivalent keyword is dynamic, making this a cross-language surprise at t7.

About DEBT scoring →

Also Known As

LSB static:: late static binding PHP

TL;DR

static:: refers to the class actually called at runtime rather than the class where the method is defined, enabling polymorphic static methods.

Explanation

In PHP, self:: always refers to the class where the method is written, even if called on a subclass. Late static binding (PHP 5.3+) uses static:: to refer to the class actually invoked at runtime. This is essential for static factory methods and the ActiveRecord pattern, where subclasses should return instances of themselves rather than the parent. get_called_class() provides the string equivalent. Overuse of static methods (as opposed to instance methods with dependency injection) can complicate testing.

Common Misconception

self:: and static:: are interchangeable in PHP class methods. self:: always refers to the class where the method is defined. static:: refers to the class that was actually called at runtime — in inheritance chains, static:: follows the child class while self:: stays fixed to the parent.

Why It Matters

Late static binding (static::) refers to the class actually called at runtime rather than the class where the method is defined — essential for correct inheritance in static factory methods and fluent APIs.

Common Mistakes

  • Using self:: in a static method intended to be inherited — self:: always refers to the defining class, not the subclass.
  • Using static:: in non-inherited static utilities where self:: is the correct and clearer choice.
  • Not understanding that static:: in a non-static context refers to the class of the object, like get_class($this).
  • Forgetting that late static binding only matters when the method is inherited — in a sealed class, self:: and static:: are identical.

Code Examples

✗ Vulnerable
class Model {
    public static function create(): self { // 'self' returns Model even when called as User::create()
        return new self();
    }
}
class User extends Model {}
$user = User::create(); // Returns Model instance, not User!

// Fix: return new static(); — returns the called class
✓ Fixed
class Model {
    // static:: refers to the class that was actually called (child)
    // self:: always refers to Model — wrong for fluent factory methods
    public static function create(array $data): static {
        $instance = new static();  // static:: = called class
        foreach ($data as $k => $v) { $instance->$k = $v; }
        return $instance;
    }
    public static function tableName(): string {
        return strtolower((new \ReflectionClass(static::class))->getShortName()) . 's';
    }
}

class User extends Model {}
class Order extends Model {}

$user  = User::create(['name' => 'Alice']); // returns User instance
$order = Order::create(['total' => 99]);    // returns Order instance
echo User::tableName();  // 'users'
echo Order::tableName(); // 'orders'

Added 15 Mar 2026
Edited 22 Mar 2026
Views 25
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 10 Perplexity 3 Unknown AI 3 Ahrefs 2 Majestic 1 Google 1
crawler 19 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Use static:: instead of self:: when the method needs to refer to the actual called class in an inheritance hierarchy, not the class where it is defined
📦 Applies To
PHP 5.3+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
self:: used in static method inherited by child class where child-specific behaviour is intended
Auto-detectable: ✓ Yes phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Class Tests: Update

✓ schema.org compliant