Introduction: One small letter that changes everything
\n\nImagine: you're writing a cool PHP framework or just a library for your project. Everything works perfectly, but a month later you notice that child classes are not behaving as you expected. You create an object, and it — bam! — returns an instance of the parent class. Sound familiar? Welcome to the club of those who have encountered new self vs. new static.
\n\nThis question on Stack Overflow has gathered thousands of views, and for good reason. The difference between self and static in PHP is not just syntactic sugar, but a fundamental mechanism that can either save your project or turn it into a maintenance nightmare. In 2025, as PHP continues to evolve, understanding Late Static Binding has become a mandatory skill for any self-respecting developer.
In this article, we won't just rehash the documentation. We'll break down real-world cases, show anti-patterns, and give clear best practices that you can apply today. Let's go!
\n\nMain part: self vs. static — the battle for context
\n\n1. self — the compile-time conservative
\n\nThe self keyword in PHP always refers to the class in which it is written. Think of it as an old, reliable friend who never changes. When you write new self() in a parent class, this code will always create an object of that exact parent class — even if a child class calls it.
<?php\nclass Animal {\n public static function create() {\n return new self(); // Always Animal\n }\n}\n\nclass Dog extends Animal {\n // Inherits create()\n}\n\n$dog = Dog::create();\necho get_class($dog); // Outputs: Animal\n?>\n\nSee? We called the method on the Dog class, but got an Animal. This often comes as a surprise to beginners. What's the catch? The catch is that self is resolved at compile time. PHP "seals" the reference to the class where the method is declared, and no inheritance magic can change that.
2. static — the late-binding revolutionary
\n\nNow static is the complete opposite. It works at the moment the method is called and determines which class called it. This is Late Static Binding, introduced in PHP 5.3.0.
<?php\nclass Animal {\n public static function create() {\n return new static(); // Creates an instance of the class that called the method\n }\n}\n\nclass Dog extends Animal {\n // Inherits create()\n}\n\n$dog = Dog::create();\necho get_class($dog); // Outputs: Dog\n?>\n\nWhat a twist! Now Dog::create() returns a dog, not an abstract animal. static looks at who called the method and creates an object of that exact class. This provides incredible flexibility when building class hierarchies.
3. When to use self and when to use static?
\n\nThe golden rule: use self when you need a hard binding to the current class, and static when you want child classes to be able to override the behavior.
Here are a few specific scenarios:
\n\nScenario A: Factory methods (Use static)
\nA classic example is the Factory Method pattern. You want each child class to create itself.
\n\n<?php\nabstract class Vehicle {\n abstract public function getType(): string;\n\n public static function create(): static {\n return new static();\n }\n}\n\nclass Car extends Vehicle {\n public function getType(): string {\n return 'Car';\n }\n}\n\nclass Bike extends Vehicle {\n public function getType(