When to Use parent::, self::, and static:: in PHP OOP

This guide explains the differences between PHP's parent::, self::, and static:: keywords, shows how they behave in inheritance hierarchies with concrete code examples, and offers practical advice on when to choose each form to avoid common pitfalls.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
When to Use parent::, self::, and static:: in PHP OOP

What is parent:: ?

When a child class calls a method defined in its parent, parent:: forces the execution of the parent implementation instead of the overridden one.

class BaseTestCase {
    public function setUp(): void {
        echo 'Run base test case set up here...';
    }
}
(new BaseTestCase())->setUp();

Extending this class without overriding setUp simply runs the parent method:

class FeatureTest extends BaseTestCase {}
(new FeatureTest())->setUp(); // outputs: Run base test case set up here...

If the child overrides setUp and calls $this->setUp(), a recursive loop occurs and the script crashes with an out‑of‑memory error.

class FeatureTest extends BaseTestCase {
    public function setUp(): void {
        $this->setUp(); // recursive call
        echo 'Run extra feature test set up here...';
    }
}
(new FeatureTest())->setUp(); // Fatal error: out of memory

Replacing the recursive call with parent::setUp() correctly invokes the parent method once and then runs the child‑specific code.

class FeatureTest extends BaseTestCase {
    public function setUp(): void {
        parent::setUp();
        echo 'Run extra feature test set up here...';
    }
}
(new FeatureTest())->setUp(); // outputs both messages

What is self:: ?

self::

accesses static members defined in the class where the method is written, ignoring inheritance overrides.

class Model {
    public static string $connection = 'mysql';
    public function makeConnection(): void {
        echo 'Making connection to: '.self::$connection;
    }
}
class User extends Model {
    public static string $connection = 'postgres';
}
(new Model())->makeConnection(); // Making connection to: mysql
(new User())->makeConnection(); // Making connection to: mysql

Adding an overriding makeConnection method to User makes self::$connection refer to the property defined in User:

class User extends Model {
    public static string $connection = 'postgres';
    public function makeConnection(): void {
        echo 'Making connection to: '.self::$connection;
    }
}
(new User())->makeConnection(); // Making connection to: postgres

What is static:: ?

static::

uses PHP's late static binding, meaning the static member is resolved based on the runtime class that invoked the method.

class Model {
    public static $connection = 'mysql';
    public function makeConnection() {
        echo 'Making connection to: '.static::$connection;
    }
}
class User extends Model {
    public static $connection = 'postgres';
}
(new Model())->makeConnection(); // Making connection to: mysql
(new User())->makeConnection(); // Making connection to: postgres

This behavior differs from self:: because the property lookup follows the actual class of the object, not the class where the method was originally defined.

For more details, see the PHP documentation on late static bindings: https://www.php.net/manual/en/language.oop5.late-static-bindings.php

According to the PHP docs, “late static binding” means that static:: resolves using runtime information rather than the class where the method is defined.

When to use self:: vs. static:: ?

If you intend your class to be extended and want overridden static members to be respected, prefer static::. This ensures child classes see their own values.

If you deliberately want to lock the behavior to the class where the method is written—perhaps because the class is final or you want to avoid inheritance side effects—use self::. Combining self:: with the final keyword can guarantee that the class will not be subclassed, eliminating accidental overrides.

In practice, choose the form that matches your design intent: use static:: for extensible, polymorphic code, and self:: for closed, non‑extendable implementations.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PHPOOPInheritancestaticparentselflate static binding
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.