PHP: When do you use self and when $this?

Inside a PHP class there are two ways to reach your own class: with $this-> and with self::. The basic rule is quickly explained. It gets interesting with the third keyword, which most people overlook.

The basic rule

$this-> refers to the instance, self:: to the class:

<?php
class Config {
  public const VERSION = '1.0';    // belongs to the class
  public static int $counter = 0;  // belongs to the class
  public string $name = 'instance'; // belongs to the instance

  public function show(): void {
    echo self::VERSION;    // constant -> self::
    echo self::$counter;   // static   -> self::
    echo $this->name;      // instance -> $this->
  }
}
?>

A way to remember it: does the thing exist even when no object has been created yet? Then self::. Does it exist per object? Then $this->.

The difference is easy to show. Static properties are shared by all instances, instance properties are not:

Config::$counter via $a: 5, via $b: 5
$a->name: A, $b->name: B

$this does not exist in static methods

Obvious, but you get to know the error message sooner or later anyway:

<?php
class Test {
  public int $value = 42;

  public static function staticMethod(): string {
    return (string) $this->value;   // does not work
  }
}
?>

The result:

Error: Using $this when not in object context

Note that this is an Error and not a warning. Your script therefore aborts at that point unless you catch it.

And now the part that actually matters: static

Besides self:: there is also static::. The difference only becomes apparent once you derive from a class — and then it becomes apparent all the more clearly.

  • self is bound to the class the line is written in.
  • static is bound to the class the call was made through.

This is called late static binding and has existed since PHP 5.3. An example:

<?php
class Base {
  public static function withSelf(): object   { return new self(); }
  public static function withStatic(): object { return new static(); }
}

class Derived extends Base {}
?>

And this is what comes out:

Derived::withSelf()   gives Base
Derived::withStatic() gives Derived

That is the classic case: you write a factory method in a base class, derive from it, and still always get objects of the base class. The mistake is new self() instead of new static().

The same happens with overridden static methods:

<?php
class Parents {
  public static function name(): string { return 'Parent'; }
  public static function viaSelf(): string   { return self::name(); }
  public static function viaStatic(): string { return static::name(); }
}

class Child extends Parents {
  public static function name(): string { return 'Child'; }
}
?>
Child::viaSelf()   => Parent
Child::viaStatic() => Child

So self::name() calls the base class’s method, even though Child has overridden it.

Constants are affected too

This case gets mentioned less often, but occurs just as frequently in practice. Constants in a base class are a widespread configuration pattern:

<?php
class Config {
  public const VERSION = '1.0';

  public function show(): void {
    echo self::VERSION;
    echo static::VERSION;
  }
}

class NewConfig extends Config {
  public const VERSION = '2.0';
}
?>

For an object of class NewConfig:

self::VERSION      => 1.0
static::VERSION    => 2.0

self::VERSION returns the base class’s constant, even though the derived class has overridden it. And because neither an error nor a warning occurs here, this kind of thing often goes unnoticed for a long time.

Summary

  • $this-> for everything that belongs to the instance.
  • self:: for constants, static properties and static methods.
  • static:: whenever derived classes should be able to override the behaviour.
  • When in doubt, use new static() rather than new self() in factory methods.
  • $this in a static method is an Error, not null.

About Netcup (advertisement)

The German host Netcup offers, among other things, affordable and powerful web hosting packages, KVM-based root servers and dedicated servers. With our voucher codes you can save even more (6€ off your first order, 30% off all KVM-based root servers, ...).