PHP: Wann nimmt man self und wann $this?

In einer PHP-Klasse kann man auf zwei Arten auf die eigene Klasse zugreifen: mit $this-> und mit self::. Die Grundregel ist schnell erklärt. Interessant wird es beim dritten Schlüsselwort, das die meisten übersehen.

Die Grundregel

$this-> bezieht sich auf die Instanz, self:: auf die Klasse:

<?php
class Konfig {
  public const VERSION = '1.0';   // gehört zur Klasse
  public static int $zaehler = 0; // gehört zur Klasse
  public string $name = 'instanz'; // gehört zur Instanz

  public function zeig(): void {
    echo self::VERSION;    // Konstante  -> self::
    echo self::$zaehler;   // statisch   -> self::
    echo $this->name;      // Instanz    -> $this->
  }
}
?>

Merken kann man sich das so: Existiert die Sache auch dann, wenn noch gar kein Objekt erzeugt wurde? Dann self::. Gibt es sie pro Objekt? Dann $this->.

Der Unterschied lässt sich gut zeigen. Statische Eigenschaften teilen sich alle Instanzen, Instanzeigenschaften nicht:

Konfig::$zaehler über $a: 5, über $b: 5
$a->name: A, $b->name: B

$this gibt es in statischen Methoden nicht

Naheliegend, aber die Fehlermeldung kennt man trotzdem irgendwann:

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

  public static function statisch(): string {
    return (string) $this->wert;   // geht nicht
  }
}
?>

Das Ergebnis:

Error: Using $this when not in object context

Beachte dabei, dass es sich um einen Error handelt und nicht um eine Warnung. Dein Skript bricht an dieser Stelle also ab, wenn du den Fehler nicht abfängst.

Und jetzt der eigentlich wichtige Teil: static

Neben self:: gibt es noch static::. Der Unterschied fällt erst auf, sobald du von einer Klasse ableitest — und dann fällt er dafür umso deutlicher auf.

  • self wird an die Klasse gebunden, in der die Zeile steht.
  • static wird an die Klasse gebunden, über die aufgerufen wurde.

Das nennt sich Late Static Binding und gibt es seit PHP 5.3. Ein Beispiel:

<?php
class Basis {
  public static function mitSelf(): object   { return new self(); }
  public static function mitStatic(): object { return new static(); }
}

class Abgeleitet extends Basis {}
?>

Und das kommt dabei heraus:

Abgeleitet::mitSelf()   ergibt Basis
Abgeleitet::mitStatic() ergibt Abgeleitet

Das ist der Klassiker: Du schreibst eine Factory-Methode in einer Basisklasse, leitest ab, und bekommst trotzdem immer Objekte der Basisklasse. Der Fehler ist new self() statt new static().

Dasselbe passiert bei überschriebenen statischen Methoden:

<?php
class Eltern {
  public static function name(): string { return 'Eltern'; }
  public static function ueberSelf(): string   { return self::name(); }
  public static function ueberStatic(): string { return static::name(); }
}

class Kind extends Eltern {
  public static function name(): string { return 'Kind'; }
}
?>
Kind::ueberSelf()   => Eltern
Kind::ueberStatic() => Kind

self::name() ruft also die Methode der Basisklasse auf, obwohl Kind sie überschrieben hat.

Auch Konstanten sind betroffen

Dieser Fall wird seltener erwähnt, kommt in der Praxis aber genauso oft vor. Konstanten in einer Basisklasse sind ein verbreitetes Konfigurationsmuster:

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

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

class KonfigNeu extends Konfig {
  public const VERSION = '2.0';
}
?>

Bei einem Objekt der Klasse KonfigNeu:

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

self::VERSION liefert die Konstante der Basisklasse, obwohl die abgeleitete Klasse sie überschrieben hat. Und weil hier weder ein Fehler noch eine Warnung auftritt, fällt so etwas oft lange nicht auf.

Zusammenfassung

  • $this-> für alles was zur Instanz gehört.
  • self:: für Konstanten, statische Eigenschaften und statische Methoden.
  • static:: immer dann, wenn abgeleitete Klassen das Verhalten überschreiben können sollen.
  • Im Zweifel bei Factory-Methoden new static() statt new self().
  • $this in einer statischen Methode ist ein Error, kein null.

Hinweis zu Netcup (Werbung)

Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).