self, static, and parent in PHP — What's the Real Difference and When to Use Each
In PHP, object-oriented programming gives us several powerful keywords—self
, static
, and parent
—to refer to classes within the class hierarchy. While they may seem similar, each has very specific behaviors, especially when dealing with inheritance, method resolution, and instantiation.
Understanding these keywords deeply is crucial for writing clean, predictable, and extensible code.
🔹 self
: The Declaring Class
self
refers to the class where the code is written, not where it is called from. This is a compile-time reference.
class A {
public static function who() {
echo "A\n";
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo "B\n";
}
}
B::test(); // Output: A
Even though B
extends A
, calling B::test()
still prints A
because self::who()
is bound to class A. This is not polymorphic.
🔹 static
: Late Static Binding
static
uses late static binding, meaning it resolves to the class that was actually called at runtime, even if it’s a subclass. This is runtime-bound.
class A {
public static function who() {
echo "A\n";
}
public static function test() {
static::who();
}
}
class B extends A {
public static function who() {
echo "B\n";
}
}
B::test(); // Output: B
Here, static::who()
correctly resolves to class B
. This is polymorphic and what you want when you expect child classes to override behavior.
Use static
when:
- You expect inheritance
- You want the behavior to be overridden correctly
- You are working with factories, fluent APIs, or interfaces with
static
return types
🔹 parent
: Accessing the Superclass
parent
is used to call methods from the immediate parent class. It’s strictly for accessing the parent’s implementation, often inside an override.
class A {
public function greet() {
echo "Hello from A\n";
}
}
class B extends A {
public function greet() {
parent::greet();
echo "And hello from B\n";
}
}
$b = new B();
$b->greet();
Output:
Hello from A
And hello from B
Use parent
when:
- You override a method but still want to call the parent’s version
- You're working in an inheritance chain and want to build on base behavior
🔍 Comparison Summary
Keyword | Bound At | Refers To | Use Case |
---|---|---|---|
self | Compile-time | Class where code is written | Internal helper methods, fixed behavior |
static | Runtime | Class that was called | Factory methods, polymorphic behavior |
parent | Compile-time | Immediate parent class | Overridden methods needing base behavior |
✅ Real-World Considerations
self
can break polymorphism. Be cautious when writing base class methods that useself
, as they won't behave well when extended.static
is powerful but introduces complexity. Use it for factories or fluent interfaces when subclassing is expected.parent
is safe but very specific. Don't use it unless you're overriding methods and still need parent logic.
💡 Bonus Tip
When using static methods that return new instances (new static()
), avoid new self()
unless you're sure that the method won’t be extended or overridden. Even in a final
class, using static
is often more future-proof.
Understanding these keywords isn't just about syntax—it’s about design. Use the right keyword for the right behavior, and your codebase will be easier to maintain, less error-prone, and ready for change.
Comments ()