Wann sollte man sich über $ this verwenden?


Antworten:


1728

Kurze Antwort

Verwenden Sie $thisdiese Option , um auf das aktuelle Objekt zu verweisen. Verwenden Sie selfdiese Option , um auf die aktuelle Klasse zu verweisen. Mit anderen Worten, $this->memberfür nicht statische Elemente verwenden, self::$memberfür statische Elemente verwenden.

Vollständige Antwort

Hier ist ein Beispiel für die korrekte Verwendung von $thisund selffür nicht statische und statische Elementvariablen:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?>

Hier ist ein Beispiel für die falsche Verwendung von $thisund selffür nicht statische und statische Elementvariablen:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo self::$non_static_member . ' '
           . $this->static_member;
    }
}

new X();
?>

Hier ist ein Beispiel für Polymorphismus mit $thisfür Elementfunktionen:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        $this->foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

Hier ist ein Beispiel für die Unterdrückung des polymorphen Verhaltens mithilfe selfvon Elementfunktionen:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        self::foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

Die Idee ist, dass $this->foo()die foo()Member-Funktion aufgerufen wird, was auch immer der genaue Typ des aktuellen Objekts ist. Wenn das Objekt von ist type X, ruft es somit auf X::foo(). Wenn das Objekt von ist type Y, ruft es auf Y::foo(). Aber mit self :: foo () X::foo()wird immer aufgerufen.

Von http://www.phpbuilder.com/board/showthread.php?t=10354489 :

Von http://board.phpbuilder.com/member.php?145249-laserlight


330
Diese Antwort ist zu simpel. Wie in anderen Antworten angegeben, selfwird mit dem Bereichsauflösungsoperator verwendet ::, um auf die aktuelle Klasse zu verweisen. Dies kann sowohl in statischen als auch in nicht statischen Kontexten erfolgen. Darüber hinaus ist es völlig legal, $thisstatische Methoden aufzurufen (aber keine Referenzfelder).
Artefacto

50
Erwägen Sie auch die Verwendung von static :: anstelle von :: self, wenn Sie 5.3+ verwenden. Andernfalls kann es zu unerklärlichen Kopfschmerzen kommen. In meiner Antwort unten erfahren Sie, warum.
Sqoo

25
-1. Diese Antwort ist irreführend. Lesen Sie die anderen Antworten, um weitere Informationen zu erhalten.
Pacerier

6
Es mag zu stark vereinfacht sein, aber es hat meine grundlegende Frage beantwortet, ohne dass mein Kopf explodiert. Ich habe einige weitere Informationen erhalten, die ich weiter unten als hilfreich empfand, aber im Moment habe ich nur versucht herauszufinden, warum ich meine Klassenattribute mit $ this-> attrib und die Klassenkonstanten mit self :: constant getroffen habe. Dies half mir, das besser zu verstehen
MydKnight

Was ist mit $this::?
James

742

Das Schlüsselwort self bezieht sich NICHT nur auf die 'aktuelle Klasse', zumindest nicht in einer Weise, die Sie auf statische Mitglieder beschränkt. selfBietet im Kontext eines nicht statischen Elements auch eine Möglichkeit, die vtable ( siehe Wiki auf vtable ) für das aktuelle Objekt zu umgehen . So wie Sie parent::methodName()die übergeordnete Version einer Funktion aufrufen können, können Sie auch self::methodName()die aktuelle Klassenimplementierung einer Methode aufrufen.

class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();

Dies wird Folgendes ausgeben:

Hallo, ich bin Ludwig der Geek
Auf Wiedersehen von Ludwig die Person

sayHello()Verwendet den $thisZeiger, sodass die vtable zum Aufrufen aufgerufen wird Geek::getTitle(). sayGoodbye()verwendet self::getTitle(), daher wird die vtable nicht verwendet und Person::getTitle()aufgerufen. In beiden Fällen handelt es sich um die Methode eines instanziierten Objekts und wir haben Zugriff auf den $thisZeiger innerhalb der aufgerufenen Funktionen.


3
Diese Antwort wäre sogar noch besser, wenn Sie eher mit einer allgemeinen Regel als mit einer Ausnahme beginnen würden. Es ist eine Frage des Stils, nicht des technischen Fachwissens. Dies ist das beste Beispiel, das ich je für den Unterschied zwischen self :: und $ this-> gesehen habe, aber es ist eine Schande, dies zu verbergen, indem man zuerst einen Begriff widerlegt.
Adjwilli

3
@adjwilli: Warum ist das ein schlechter Stil? Erhöht es nicht das Bewusstsein, wenn die Erwartung (These) des OP zuerst missbilligt wird (Antithese) und dann die Erklärung als Synthese gegeben wird?
hakre

1
Ich finde "aktuelle Klasse" wirklich problematisch. Da diese Wortkombination sowohl als "die Klasse, in der selfsich befindet" / "die Klassendefinition, die ein wörtlicher Teil von" ist, als auch als "die Klasse des Objekts" (was tatsächlich der Fall wäre static) verstanden werden kann.
Jakumi

Was ist mit $this::?
James

1
@ James - es gibt keinen guten Grund zu verwenden $this::; Alle möglichen Fälle werden bereits durch häufig verwendete Syntaxen abgedeckt. Je nachdem , was Sie meinen, Verwendung $this->, self::oder static::.
ToolmakerSteve

461

NICHT VERWENDEN self::, verwendenstatic::

Es gibt noch einen weiteren Aspekt des Selbst: der erwähnenswert ist. Ärgerlicherweise self::bezieht sich der Geltungsbereich zum Zeitpunkt der Definition und nicht zum Zeitpunkt der Ausführung . Betrachten Sie diese einfache Klasse mit zwei Methoden:

class Person
{

    public static function status()
    {
        self::getStatus();
    }

    protected static function getStatus()
    {
        echo "Person is alive";
    }

}

Wenn wir anrufen, sehen Person::status()wir "Person lebt". Überlegen Sie nun, was passiert, wenn wir eine Klasse erstellen, die davon erbt:

class Deceased extends Person
{

    protected static function getStatus()
    {
        echo "Person is deceased";
    }

}

Beim Aufrufen wird Deceased::status()erwartet, dass "Person ist verstorben" angezeigt wird. Wir sehen jedoch "Person lebt", da der Bereich die ursprüngliche Methodendefinition enthält, als der Aufruf von self::getStatus()definiert wurde.

PHP 5.3 hat eine Lösung. Der static::Auflösungsoperator implementiert "späte statische Bindung", was eine ausgefallene Art zu sagen ist, dass sie an den Umfang der aufgerufenen Klasse gebunden ist. Ändern Sie die Zeile in status()zu static::getStatus() , und die Ergebnisse sind das, was man erwarten würde. In älteren Versionen von PHP müssen Sie einen Kludge finden, um dies zu tun.

Siehe PHP-Dokumentation

Also, um die Frage nicht wie gestellt zu beantworten ...

$this->bezieht sich auf das aktuelle Objekt (eine Instanz einer Klasse), während static::sich auf eine Klasse bezieht


6
Was ist mit Klassenkonstanten?
Kevin Bond

53
"Wenn wir Deceased :: status () aufrufen, erwarten wir" Person ist verstorben "". Nein. Dies ist ein statischer Funktionsaufruf, sodass kein Polymorphismus vorliegt.
Cquezel

2
Von allen Fehlern von PHP halte ich das überhaupt nicht für verrückt. Wie sonst würden sie es Codierern erlauben, Methoden für die aktuelle Klasse zu bestimmen (anstatt sie in der vtable nachzuschlagen)? Wenn sie es anders benannt hätten (vielleicht mit führenden Unterstrichen), würden Leute, die dieses Feature wollen, es als hässlich kritisieren. Andernfalls scheint es immer leicht verwirrte Leute zu geben, die es als "wahnsinniges" Verhalten kritisieren, ohne zu wissen, wie der Methodenversand überhaupt funktioniert.
Der

2
Das Beispiel erscheint mir verwirrend: Ich sehe die getStatusMethode als eine, die ich für eine Klasseninstanz aufrufen würde, nicht für eine Klasse.
Jānis Elmeris

1
@Sqoo - zu sagen " VERWENDEN SIE NICHT self ::, verwenden Sie static ::" ist ein seltsamer Punkt - das sind absichtlich nicht die gleichen Operationen. Ich denke, der Punkt, den Sie wirklich ansprechen, ist: "Es ist klarer, wenn Sie den tatsächlichen Klassennamen 'MyClass ::' anstelle von 'self ::' verwenden . Das heißt, wenn Sie das Verhalten von wollen self::, können Sie das weniger bekommen verwirrenderweise unter Verwendung des spezifischen Klassennamens, z MyClass::. B.
ToolmakerSteve

248

Um wirklich zu verstehen, worüber wir sprechen, wenn wir über selfversus sprechen $this, müssen wir uns tatsächlich mit dem befassen, was auf konzeptioneller und praktischer Ebene vor sich geht. Ich habe nicht das Gefühl, dass eine der Antworten dies angemessen macht. Hier ist mein Versuch.

Lassen Sie uns zunächst darüber sprechen, was eine Klasse und ein Objekt sind.

Klassen und Objekte, konzeptionell

Was ist eine Klasse ? Viele Leute definieren es als Blaupause oder Vorlage für ein Objekt. In der Tat können Sie hier mehr über Klassen in PHP lesen . Und bis zu einem gewissen Grad ist es das wirklich. Schauen wir uns eine Klasse an:

class Person {
    public $name = 'my name';
    public function sayHello() {
        echo "Hello";
    }
}

Wie Sie sehen können, gibt es für diese Klasse eine Eigenschaft namens $nameund eine Methode (Funktion) sayHello().

Es ist sehr wichtig zu beachten, dass die Klasse eine statische Struktur ist. Dies bedeutet, dass die Personeinmal definierte Klasse überall, wo Sie sie betrachten, immer dieselbe ist.

Ein Objekt hingegen ist eine sogenannte Instanz einer Klasse. Das bedeutet, dass wir den "Entwurf" der Klasse nehmen und daraus eine dynamische Kopie erstellen. Diese Kopie ist jetzt speziell an die Variable gebunden, in der sie gespeichert ist. Daher sind alle Änderungen an einer Instanz lokal für diese Instanz.

$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"

Wir erstellen neue Instanzen einer Klasse mit dem newOperator.

Daher sagen wir, dass eine Klasse eine globale Struktur und ein Objekt eine lokale Struktur ist. Mach dir keine Sorgen um diese lustige ->Syntax, wir werden gleich darauf eingehen.

Eine andere Sache, über die wir sprechen sollten, ist, dass wir überprüfen können , ob eine Instanz instanceofeine bestimmte Klasse ist: $bob instanceof Persondie einen Booleschen Wert zurückgibt, wenn die $bobInstanz mit der PersonKlasse oder einem untergeordneten Element von erstellt wurde Person.

Zustand definieren

Lassen Sie uns ein wenig untersuchen, was eine Klasse tatsächlich enthält. Es gibt 5 Arten von "Dingen", die eine Klasse enthält:

  1. Eigenschaften - Stellen Sie sich diese als Variablen vor, die jede Instanz enthalten wird.

    class Foo {
        public $bar = 1;
    }
  2. Statische Eigenschaften - Stellen Sie sich diese als Variablen vor, die auf Klassenebene gemeinsam genutzt werden. Dies bedeutet, dass sie niemals von jeder Instanz kopiert werden.

    class Foo {
        public static $bar = 1;
    }
  3. Methoden - Dies sind Funktionen, die jede Instanz enthält (und mit Instanzen arbeitet).

    class Foo {
        public function bar() {}
    }
  4. Statische Methoden - Dies sind Funktionen, die von der gesamten Klasse gemeinsam genutzt werden. Sie arbeiten nicht mit Instanzen, sondern nur mit den statischen Eigenschaften.

    class Foo {
        public static function bar() {}
    }
  5. Konstanten - Klassenaufgelöste Konstanten. Hier nicht tiefer gehen, sondern der Vollständigkeit halber hinzufügen:

    class Foo {
        const BAR = 1;
    }

Im Grunde speichern wir Informationen über den Klassen- und Objektcontainer mithilfe von "Hinweisen" zu statischen Informationen, die angeben, ob die Informationen gemeinsam genutzt werden (und daher statisch sind) oder nicht (und daher dynamisch).

Zustand und Methoden

Innerhalb einer Methode wird die Instanz eines Objekts durch die $thisVariable dargestellt. Der aktuelle Status dieses Objekts ist vorhanden, und das Mutieren (Ändern) einer Eigenschaft führt zu einer Änderung dieser Instanz (jedoch nicht anderer).

Wenn eine Methode statisch aufgerufen wird, ist die $thisVariable nicht definiert . Dies liegt daran, dass einem statischen Aufruf keine Instanz zugeordnet ist.

Das Interessante dabei ist, wie statische Anrufe getätigt werden. Sprechen wir also darüber, wie wir auf den Staat zugreifen:

Zugriffsstatus

Nachdem wir diesen Status gespeichert haben, müssen wir darauf zugreifen. Dies kann etwas knifflig werden (oder weit mehr als ein bisschen). Teilen wir dies also in zwei Gesichtspunkte auf: von außerhalb einer Instanz / Klasse (z. B. von einem normalen Funktionsaufruf oder vom globalen Bereich) und innerhalb einer Instanz / class (aus einer Methode für das Objekt).

Von außerhalb einer Instanz / Klasse

Von außerhalb einer Instanz / Klasse sind unsere Regeln recht einfach und vorhersehbar. Wir haben zwei Operatoren und jeder teilt uns sofort mit, ob es sich um eine Instanz oder eine statische Klasse handelt:

  • ->- Objektoperator - Dies wird immer verwendet, wenn wir auf eine Instanz zugreifen.

    $bob = new Person;
    echo $bob->name;

    Es ist wichtig zu beachten, dass das Aufrufen Person->fookeinen Sinn ergibt (da Persones sich um eine Klasse handelt, nicht um eine Instanz). Daher ist dies ein Analysefehler.

  • ::- Bereichsauflösungsoperator - Wird immer verwendet, um auf eine statische Eigenschaft oder Methode der Klasse zuzugreifen.

    echo Foo::bar()

    Darüber hinaus können wir eine statische Methode für ein Objekt auf dieselbe Weise aufrufen:

    echo $foo::bar()

    Es ist äußerst wichtig zu beachten, dass die Instanz des Objekts , wenn wir dies von außen tun , vor der bar()Methode verborgen bleibt . Das heißt, es ist genau das gleiche wie beim Laufen:

    $class = get_class($foo);
    $class::bar();

Daher $thisist im statischen Aufruf nicht definiert.

Aus dem Inneren einer Instanz / Klasse

Hier ändern sich die Dinge ein bisschen. Es werden dieselben Operatoren verwendet, aber ihre Bedeutung wird erheblich unscharf.

Der Objektoperator -> wird weiterhin verwendet, um den Instanzstatus des Objekts aufzurufen.

class Foo {
    public $a = 1;
    public function bar() {
        return $this->a;
    }
}

Das Aufrufen der bar()Methode für $foo(eine Instanz von Foo) mit dem Objektoperator: $foo->bar()führt zur Version von der Instanz von $a.

So erwarten wir es also.

Die Bedeutung des ::Operators ändert sich jedoch. Dies hängt vom Kontext des Aufrufs der aktuellen Funktion ab:

  • In einem statischen Kontext

    In einem statischen Kontext sind alle mit verwendeten Anrufe ::auch statisch. Schauen wir uns ein Beispiel an:

    class Foo {
        public function bar() {
            return Foo::baz();
        }
        public function baz() {
            return isset($this);
        }
    }

    Der Aufruf Foo::bar()wird der Anruf baz()statisch Methode, und daher $thiswird nicht aufgefüllt werden. Es ist erwähnenswert, dass dies in neueren Versionen von PHP (5.3+) einen E_STRICTFehler auslöst , da wir nicht statische Methoden statisch aufrufen.

  • Innerhalb eines Instanzkontexts

    In einem Instanzkontext hingegen ::hängen Anrufe, die mit ausgeführt werden, vom Empfänger des Anrufs ab (der Methode, die wir aufrufen). Wenn die Methode definiert ist als static, wird ein statischer Aufruf verwendet. Ist dies nicht der Fall, werden die Instanzinformationen weitergeleitet.

    Wenn Sie sich also den obigen Code ansehen, $foo->bar()wird der Aufruf zurückgegeben true, da der "statische" Aufruf innerhalb eines Instanzkontexts erfolgt.

Sinn ergeben? Das habe ich nicht gedacht. Es ist verwirrend.

Tastenkürzel

Da das Zusammenbinden von Elementen mithilfe von Klassennamen ziemlich schmutzig ist, bietet PHP drei grundlegende "Verknüpfungs" -Schlüsselwörter, um die Auflösung des Bereichs zu vereinfachen.

  • self- Dies bezieht sich auf den aktuellen Klassennamen. Ist self::baz()also dasselbe wie Foo::baz()innerhalb der FooKlasse (jede Methode darauf).

  • parent - Dies bezieht sich auf das übergeordnete Element der aktuellen Klasse.

  • static- Dies bezieht sich auf die aufgerufene Klasse. Dank der Vererbung können untergeordnete Klassen Methoden und statische Eigenschaften überschreiben. staticWenn wir sie also anstelle eines Klassennamens aufrufen, können wir feststellen, woher der Anruf stammt und nicht auf der aktuellen Ebene.

Beispiele

Der einfachste Weg, dies zu verstehen, besteht darin, sich einige Beispiele anzusehen. Lassen Sie uns eine Klasse auswählen:

class Person {
    public static $number = 0;
    public $id = 0;
    public function __construct() {
        self::$number++;
        $this->id = self::$number;
    }
    public $name = "";
    public function getName() {
        return $this->name;
    }
    public function getId() {
        return $this->id;
    }
}

class Child extends Person {
    public $age = 0;
    public function __construct($age) {
        $this->age = $age;
        parent::__construct();
    }
    public function getName() {
        return 'child: ' . parent::getName();
    }
}

Jetzt betrachten wir hier auch die Vererbung. Ignorieren Sie für einen Moment, dass dies ein schlechtes Objektmodell ist, aber schauen wir uns an, was passiert, wenn wir damit spielen:

$bob = new Person;
$bob->name = "Bob";
$adam = new Person;
$adam->name = "Adam";
$billy = new Child;
$billy->name = "Billy";
var_dump($bob->getId()); // 1
var_dump($adam->getId()); // 2
var_dump($billy->getId()); // 3

Der ID-Zähler wird also von beiden Instanzen und den untergeordneten Elementen gemeinsam genutzt (da wir selffür den Zugriff darauf verwenden. Wenn wir ihn verwenden static, können wir ihn in einer untergeordneten Klasse überschreiben).

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

Beachten Sie, dass wir die Person::getName() Instanzmethode jedes Mal ausführen . Aber wir verwenden das parent::getName(), um es in einem der Fälle zu tun (dem untergeordneten Fall). Dies macht diesen Ansatz leistungsfähig.

Wort der Vorsicht # 1

Beachten Sie, dass der aufrufende Kontext bestimmt, ob eine Instanz verwendet wird. Deshalb:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

Ist nicht immer wahr.

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

Jetzt ist es hier wirklich komisch. Wir rufen eine andere Klasse auf, aber die $this, die an die Foo::isFoo()Methode übergeben wird, ist die Instanz von $bar.

Dies kann alle möglichen Fehler und konzeptionelle WTF-Fehler verursachen. Also ich sehr empfehlen würde die Vermeidung ::Operator aus Instanzmethoden auf irgendetwas außer den drei virtuellen „short-cut“ keywords ( static, self, und parent).

Wort der Vorsicht # 2

Beachten Sie, dass statische Methoden und Eigenschaften von allen gemeinsam genutzt werden. Das macht sie im Grunde zu globalen Variablen. Mit den gleichen Problemen, die mit Globals kommen. Daher würde ich sehr zögern, Informationen in statischen Methoden / Eigenschaften zu speichern, es sei denn, Sie sind damit einverstanden, dass sie wirklich global sind.

Wort der Vorsicht # 3

Im Allgemeinen möchten Sie das verwenden, was als Late-Static-Binding bezeichnet wird, indem Sie staticanstelle von verwenden self. Beachten Sie jedoch, dass sie nicht dasselbe sind. Daher ist es sehr kurzsichtig , zu sagen, dass immer verwenden staticstatt verwenden self. Halten Sie stattdessen an und überlegen Sie, welchen Anruf Sie tätigen möchten, und überlegen Sie, ob untergeordnete Klassen diese statische Auflösung überschreiben können Anruf.

TL / DR

Schade, geh zurück und lies es. Es mag zu lang sein, aber es ist so lang, weil dies ein komplexes Thema ist

TL / DR # 2

Ok, gut. Kurz gesagt, selfwird verwendet , um das Bezug der aktuellen Klassennamen innerhalb einer Klasse, in der, wie $thisauf die aktuelle Objekt verweist Instanz . Beachten Sie, dass dies selfeine Verknüpfung zum Kopieren / Einfügen ist. Sie können es sicher durch Ihren Klassennamen ersetzen, und es wird gut funktionieren. Ist $thisaber eine dynamische Variable, die nicht im Voraus bestimmt werden kann (und möglicherweise nicht einmal Ihre Klasse ist).

TL / DR # 3

Wenn der Objektoperator ( ->) verwendet wird, wissen Sie immer , dass es sich um eine Instanz handelt. Wenn der Scope-Resolution-Operator verwendet wird ( ::), benötigen Sie weitere Informationen zum Kontext (befinden wir uns bereits in einem Objektkontext? Befinden wir uns außerhalb eines Objekts? Usw.).


1
Wort der Vorsicht # 1: $ Dies wird nicht definiert, wenn eine statische Methode aufgerufen wird
Mark Achée

Nun ... $thiswird nicht definiert, wenn Sie "Strikte Standards" befolgen und keine statischen Methoden aufrufen, die nicht als statisch definiert sind. Ich sehe das Ergebnis, das Sie hier erklärt haben: 3v4l.org/WeHVM Einverstanden, wirklich komisch.
Mark Achée

2
Nachdem ich die lange Beschreibung vollständig gelesen hatte, fühlte ich mich faul, noch einmal nach oben zu scrollen, um sie zu verbessern. Nur ein Scherz, ich habe es positiv bewertet: D. Danke das ist sehr nützlich.
Mr_Green

3
Es wäre schön, eine klare Erklärung für den Unterschied zwischen self :: $ property und self :: property hinzuzufügen. Ich denke, das ist auch ziemlich verwirrend
Tommaso Barbugli

1
WoC # 1 verhält sich seit PHP 7 anders . Wie Foo::isFoo()statisch genannt, $thiswird es nicht definiert. Das ist meiner Meinung nach intuitiver. - Ein anderes Ergebnis ergibt sich, wenn Barvon Foo. Dann Foo::isFoo()würde sich der Aufruf tatsächlich im Instanzkontext befinden (nicht spezifisch für PHP7).
Kontrollfreak

117

self(nicht $ self) bezieht sich auf die Art der Klasse, wo , wie $thisauf die aktuelle bezieht Instanz der Klasse. selfdient zur Verwendung in statischen Elementfunktionen, um Ihnen den Zugriff auf statische Elementvariablen zu ermöglichen. $thiswird in nicht statischen Elementfunktionen verwendet und verweist auf die Instanz der Klasse, für die die Elementfunktion aufgerufen wurde.

Da thises sich um ein Objekt handelt, verwenden Sie es wie folgt:$this->member

Da selfes sich nicht um ein Objekt handelt, handelt es sich im Grunde genommen um einen Typ, der automatisch auf die aktuelle Klasse verweist. Sie verwenden ihn wie folgt:self::member


97

$this-> wird verwendet, um auf eine bestimmte Instanz der Variablen (Mitgliedsvariablen) oder Methoden einer Klasse zu verweisen.

Example: 
$derek = new Person();

$ derek ist jetzt eine bestimmte Instanz von Person. Jede Person hat einen Vor- und einen Nachnamen, aber $ derek hat einen bestimmten Vor- und Nachnamen (Derek Martin). Innerhalb der $ derek-Instanz können wir diese als $ this-> first_name und $ this-> last_name bezeichnen

ClassName :: wird verwendet, um auf diesen Klassentyp und seine statischen Variablen, statische Methoden, zu verweisen. Wenn es hilft, können Sie das Wort "statisch" mental durch "geteilt" ersetzen. Da sie gemeinsam genutzt werden, können sie nicht auf $ this verweisen, das sich auf eine bestimmte Instanz bezieht (nicht freigegeben). Statische Variablen (dh statische $ db_connection) können von allen Instanzen eines Objekttyps gemeinsam genutzt werden. Beispielsweise teilen sich alle Datenbankobjekte eine einzige Verbindung (statische $ Verbindung).

Statische Variablen Beispiel: Stellen Sie sich vor, wir haben eine Datenbankklasse mit einer einzelnen Mitgliedsvariablen: static $ num_connections; Fügen Sie dies nun in den Konstruktor ein:

function __construct()
{
    if(!isset $num_connections || $num_connections==null)
    {
        $num_connections=0;
    }
    else
    {
        $num_connections++;
    }
}

So wie Objekte Konstruktoren haben, haben sie auch Destruktoren, die ausgeführt werden, wenn das Objekt stirbt oder nicht gesetzt ist:

function __destruct()
{
    $num_connections--;
}

Jedes Mal, wenn wir eine neue Instanz erstellen, wird unser Verbindungszähler um eins erhöht. Jedes Mal, wenn wir eine Instanz zerstören oder nicht mehr verwenden, wird der Verbindungszähler um eins verringert. Auf diese Weise können wir die Anzahl der Instanzen des Datenbankobjekts überwachen, mit denen wir arbeiten:

echo DB::num_connections;

Da $ num_connections statisch (gemeinsam genutzt) ist, gibt es die Gesamtzahl der aktiven Datenbankobjekte wieder. Möglicherweise wurde diese Technik verwendet, um Datenbankverbindungen für alle Instanzen einer Datenbankklasse freizugeben. Dies geschieht, weil das Erstellen der Datenbankverbindung sehr lange dauert. Daher ist es am besten, nur eine zu erstellen und diese freizugeben (dies wird als Singleton-Muster bezeichnet).

Statische Methoden (dh öffentliche statische View :: format_phone_number ($ digits)) können verwendet werden, OHNE zuerst eines dieser Objekte zu instanziieren (dh sie verweisen nicht intern auf $ this).

Beispiel für eine statische Methode:

public static function prettyName($first_name, $last_name)
{
    echo ucfirst($first_name).' '.ucfirst($last_name);
}

echo Person::prettyName($derek->first_name, $derek->last_name);

Wie Sie sehen können, weiß die öffentliche statische Funktion PrettyName nichts über das Objekt. Es funktioniert nur mit den Parametern, die Sie übergeben, wie eine normale Funktion, die nicht Teil eines Objekts ist. Warum also die Mühe machen, wenn wir es einfach nicht als Teil des Objekts haben könnten?

  1. Wenn Sie Funktionen an Objekte anhängen, können Sie die Dinge besser organisieren, sodass Sie wissen, wo Sie sie finden.
  2. Zweitens werden Namenskonflikte verhindert. In einem großen Projekt werden wahrscheinlich zwei Entwickler getName () -Funktionen erstellen. Wenn einer einen ClassName1 :: getName () erstellt und der andere ClassName2 :: getName () erstellt, ist dies überhaupt kein Problem. Kein Konflikt. Yay statische Methoden!

SELBST :: Wenn Sie außerhalb des Objekts codieren , das über die statische Methode verfügt, auf die Sie verweisen möchten, müssen Sie es mit dem Objektnamen View :: format_phone_number ($ phone_number) aufrufen. Wenn Sie innerhalb des Objekts codieren , das über die statische Methode verfügt, auf die Sie verweisen möchten, können Sie entweder den Objektnamen View :: format_phone_number ($ pn) oder die Verknüpfung self :: format_phone_number ($ pn) verwenden

Gleiches gilt für statische Variablen: Beispiel: View :: templates_path versus self :: templates_path

Wenn wir in der DB-Klasse auf eine statische Methode eines anderen Objekts verweisen, verwenden wir den Namen des Objekts: Beispiel: Session :: getUsersOnline ();

Wenn die DB-Klasse jedoch auf ihre eigene statische Variable verweisen möchte, sagt sie einfach self: Beispiel: self :: connection;

Hoffe das hilft Dinge aufzuklären :)


Gute Antwort. Ich möchte nur darauf hinweisen, dass Sie, wenn Sie sich auf ein statisches Attribut beziehen, ein $Zeichen verwenden müssen. Zum Beispielself::$templates_path
Henrywright

30

Aus diesem Blog-Beitrag :

  • self bezieht sich auf die aktuelle Klasse
  • self kann verwendet werden, um statische Funktionen aufzurufen und statische Elementvariablen zu referenzieren
  • self kann in statischen Funktionen verwendet werden
  • self kann auch das polymorphe Verhalten durch Umgehen der vtable ausschalten
  • $this bezieht sich auf das aktuelle Objekt
  • $this kann verwendet werden, um statische Funktionen aufzurufen
  • $thissollte nicht zum Aufrufen statischer Elementvariablen verwendet werden. Verwenden Sie selfstattdessen.
  • $this kann nicht in statischen Funktionen verwendet werden

26

In PHP verwenden Sie das Schlüsselwort self, um auf statische Eigenschaften und Methoden zuzugreifen.

Das Problem ist , dass Sie ersetzen können , $this->method()mit self::method()überall, unabhängig davon , obmethod() statisch deklariert wird oder nicht. Welches sollten Sie also verwenden?

Betrachten Sie diesen Code:

class ParentClass {
    function test() {
        self::who();    // will output 'parent'
        $this->who();   // will output 'child'
    }

    function who() {
        echo 'parent';
    }
}

class ChildClass extends ParentClass {
    function who() {
        echo 'child';
    }
}

$obj = new ChildClass();
$obj->test();

In diesem Beispiel self::who()wird immer 'parent' ausgegeben, während$this->who() von der Klasse des Objekts abhängt.

Jetzt können wir sehen, dass sich self auf die Klasse bezieht, in der es aufgerufen wird, während es $thissich auf die Klasse des aktuellen Objekts bezieht .

Daher sollten Sie self nur verwenden, wenn $thises nicht verfügbar ist oder wenn Sie nicht zulassen möchten, dass Nachkommenklassen die aktuelle Methode überschreiben.


22

$thisBezieht sich innerhalb einer Klassendefinition auf das aktuelle Objekt, währendself sich auf die aktuelle Klasse bezieht.

Es ist erforderlich, mit auf ein Klassenelement zu verweisen selfund mit auf ein Objektelement zu verweisen $this.

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  

21

Hier ist ein Beispiel für die korrekte Verwendung von $ this und self für nicht statische und statische Elementvariablen:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?> 

21

Laut http://www.php.net/manual/en/language.oop5.static.php gibt es keine $self. Es gibt nur $this, um auf die aktuelle Instanz der Klasse (das Objekt) und self zu verweisen, die verwendet werden können, um auf statische Mitglieder einer Klasse zu verweisen. Hier kommt der Unterschied zwischen einer Objektinstanz und einer Klasse ins Spiel.


9
Vorschlag: Lesen Sie diese Antwort, wenn Sie mit Säure stolpern.
A20

16

Ich glaube, die Frage war nicht, ob Sie das statische Mitglied der Klasse durch Aufrufen aufrufen können ClassName::staticMember. Die Frage war, was der Unterschied zwischen self::classmemberund ist $this->classmember.

Zum Beispiel funktionieren beide der folgenden Beispiele fehlerfrei, unabhängig davon, ob Sie self::oder verwenden$this->

class Person{
    private $name;
    private $address;

    public function __construct($new_name,$new_address){
        $this->name = $new_name;
        $this->address = $new_address;
    }
}

class Person{
    private $name;
    private $address;
    public function __construct($new_name,$new_address){
        self::$name = $new_name;
        self::$address = $new_address;
    }
}

Es ist besonders lustig, dass Sie Ihre Antwort mit "Ich glaube, die Frage war nicht, ob Sie das statische Mitglied der Klasse durch Aufrufen von ClassName :: staticMember aufrufen können. Die Frage war, was der Unterschied zwischen der Verwendung von self :: classmember und $ this-> classmember ist." und dann zeigen Sie überhaupt keine Unterschiede. Tatsächlich zeigen Sie eine Instanz, in der die beiden Optionen identisch funktionieren. -1
Buttle Butkus

Trotzdem nützlich. Der Umfang war über Auflösung und dieser Teil ist im PHP-Handbuch nicht klar. Ich finde es immer noch nützlich
Renoirb

2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun

16

self bezieht sich auf die aktuelle Klasse (in der es heißt),

$thisverweist auf das aktuelle Objekt. Sie können statisch anstelle von selbst verwenden. Siehe das Beispiel:

    class ParentClass {
            function test() {
                    self::which();  // output 'parent'
                    $this->which(); // output 'child'
            }

            function which() {
                    echo 'parent';
            }
    }

    class ChildClass extends ParentClass {
            function which() {
                    echo 'child';
            }
    }

    $obj = new ChildClass();
    $obj->test();

Ausgabe: Eltern Kind


16
  • Der Objektzeiger $thisauf bezieht sich auf das aktuelle Objekt.
  • Der Klassenwert staticbezieht sich auf das aktuelle Objekt.
  • Der Klassenwert selfbezieht sich auf die genaue Klasse, in der er definiert wurde.
  • Der Klassenwert parentbezieht sich auf das übergeordnete Element der genauen Klasse, in der es definiert wurde.

Siehe das folgende Beispiel, das die Überlastung zeigt.

<?php

class A {

    public static function newStaticClass()
    {
        return new static;
    }

    public static function newSelfClass()
    {
        return new self;
    }

    public function newThisClass()
    {
        return new $this;
    }
}

class B extends A
{
    public function newParentClass()
    {
        return new parent;
    }
}


$b = new B;

var_dump($b::newStaticClass()); // B
var_dump($b::newSelfClass()); // A because self belongs to "A"
var_dump($b->newThisClass()); // B
var_dump($b->newParentClass()); // A


class C extends B
{
    public static function newSelfClass()
    {
        return new self;
    }
}


$c = new C;

var_dump($c::newStaticClass()); // C
var_dump($c::newSelfClass()); // C because self now points to "C" class
var_dump($c->newThisClass()); // C
var_dump($b->newParentClass()); // A because parent was defined *way back* in class "B"

Meistens möchten Sie sich auf die aktuelle Klasse beziehen, weshalb Sie staticoder verwenden $this. Es gibt jedoch Zeiten, in denen Sie die ursprüngliche Klasse benötigen, self unabhängig davon, was sie erweitert. (Sehr, sehr selten)


14

Da hier niemand über Leistungen sprach, ist hier ein kleiner Maßstab, den ich gemacht habe (5.6):

 Name     | Time    | Percent  
----------|---------|---------  
 $this->  | 0.99163 | 106.23%  
 self::   | 0.96912 | 103.82%  
 static:: | 0.93348 | 100%

Das sind die Ergebnisse für 2 000 000 Läufe, und hier ist der Code, den ich verwendet habe:

<?php

require '../vendor/autoload.php';

// My small class to do benchmarks
// All it does is looping over every test x times and record the
//   time it takes using `microtime(true)`
// Then, the percentage is calculated, with 100% being the quickest
// Times are being rouned for outputting only, not to calculate the percentages
$b = new Tleb\Benchmark\Benchmark(2000000);

class Foo
{
    public function calling_this()
    {
        $this->called();
    }

    public function calling_self()
    {
        self::called();
    }

    public function calling_static()
    {
        static::called();
    }

    public static function called()
    {
    }
}

$b->add('$this->',  function () { $foo = new Foo; $foo->calling_this(); });
$b->add('self::',   function () { $foo = new Foo; $foo->calling_self(); });
$b->add('static::', function () { $foo = new Foo; $foo->calling_static(); });

$b->run();

1
Das 2 000 000-malige Aufrufen der No-Op-Funktion dauert 1s. Ich muss PHP lieben.
rr-

Gutes altes PHP. :) Aber ein Anruf = 0,001 ms. Ist es so schlimm?
Tleb

Ich glaube, dies (und ähnliche Dinge) ist der Grund, warum sich Dinge wie ORMs langsam anfühlen, es sei denn, Sie zwischenspeichern Dinge, und statische Site-Generatoren sind eine Sache.
rr-

2
Es sollte theoretisch 1 Prozessortaktzyklus dauern, was ungefähr in 1 / 2e9 s = 0.5 nsdiesen Tagen macht
Buddy

Lies einfach meine Antwort noch einmal. Seien Sie vorsichtig: Es erstellt auch die Klasse . Ich weiß nicht, warum ich das useSchlüsselwort tbh nicht verwendet habe, aber ich habe kein PHP mehr, um einen Benchmark zu wiederholen, und ich habe keine Lust, ihn neu zu installieren.
Tleb

13

Wenn selfes mit dem ::Operator verwendet wird, bezieht es sich auf die aktuelle Klasse, was sowohl in statischen als auch in nicht statischen Kontexten erfolgen kann. $thisbezieht sich auf das Objekt selbst. Darüber hinaus ist es völlig legal, $thisstatische Methoden aufzurufen (aber nicht auf Felder zu verweisen).


8

Ich bin auf dieselbe Frage gestoßen und die einfache Antwort lautet:

  • $this erfordert eine Instanz der Klasse
  • self:: nicht

Wenn Sie statische Methoden oder statische Attribute verwenden und diese aufrufen möchten, ohne dass ein Objekt der Klasse instanziiert wurde, müssen Sie self:sie aufrufen, da $thisimmer ein Objekt erstellt werden muss.


7

$thisbezieht sich auf das aktuelle Klassenobjekt, selfbezieht sich auf die aktuelle Klasse (kein Objekt). Die Klasse ist die Blaupause des Objekts. Sie definieren also eine Klasse, aber Sie konstruieren Objekte.

Also mit anderen Worten, verwenden Sie self for static undthis for none-static members or methods .

Auch im Child / Parent-Szenario self / parentwird meistens verwendet, um untergeordnete und übergeordnete Klassenmitglieder und -methoden zu identifizieren.


7

Zusätzlich seit $this:: noch nicht diskutiert.

Nur zu Informationszwecken, ab PHP 5.3, wenn mit instanziierten Objekten gearbeitet wird, um den aktuellen Bereichswert zu erhalten static::, kann man alternativ $this::wie folgt verwenden.

http://ideone.com/7etRHy

class Foo
{
    const NAME = 'Foo';

    //Always Foo::NAME (Foo) due to self
    protected static $staticName = self::NAME;

    public function __construct()
    {
        echo $this::NAME;
    }

    public function getStaticName()
    {
       echo $this::$staticName;
    }
}

class Bar extends Foo
{
    const NAME = 'FooBar';

    /**
     * override getStaticName to output Bar::NAME
     */
    public function getStaticName()
    {
        $this::$staticName = $this::NAME;
        parent::getStaticName();
    }
}

$foo = new Foo; //outputs Foo
$bar = new Bar; //outputs FooBar
$foo->getStaticName(); //outputs Foo
$bar->getStaticName(); //outputs FooBar
$foo->getStaticName(); //outputs FooBar

Die Verwendung des obigen Codes ist keine übliche oder empfohlene Vorgehensweise, sondern dient lediglich der Veranschaulichung seiner Verwendung und dient eher als "Wussten Sie, dass?" in Bezug auf die Frage des Originalplakats.

Es repräsentiert auch die Verwendung von $object::CONSTANTzum Beispiel echo $foo::NAME;im Gegensatz zu$this::NAME;


5

Verwenden selfSie diese Option, wenn Sie eine Methode einer Klasse aufrufen möchten, ohne ein Objekt / eine Instanz dieser Klasse zu erstellen, wodurch RAM gespart wird (verwenden Sie manchmal self für diesen Zweck). Mit anderen Worten, es wird tatsächlich eine Methode statisch aufgerufen. Verwendung thisfür Objektperspektive.


2

Fall 1: Verwenden self kann für Klassenkonstanten verwendet werden

 Klasse KlasseA { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}}

Wenn Sie es außerhalb der Klasse aufrufen möchten, verwenden Sie, um classA::POUNDS_TO_KILOGRAMSauf die Konstanten zuzugreifen

Fall 2: Für statische Eigenschaften

Klasse classC {
     öffentliche Funktion __construct () { 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }}
}}

1

Nach php.net gibt es drei spezielle Schlüsselwörter in diesem Zusammenhang: self, parentund static. Sie werden verwendet, um über die Klassendefinition auf Eigenschaften oder Methoden zuzugreifen.

$thisAuf der anderen Seite wird eine Instanz und Methoden einer Klasse aufgerufen, solange auf diese Klasse zugegriffen werden kann.


-1

Das  Schlüsselwort self :: wird für die aktuelle Klasse verwendet und im Grunde genommen für den Zugriff auf statische Elemente, Methoden und Konstanten. In diesem Fall können Sie das statische Element, die Methode und die Funktionen jedoch nicht aufrufen.

Sie können das Schlüsselwort self :: in einer anderen Klasse verwenden und auf die statischen Elemente, Methoden und Konstanten zugreifen. Wann wird es von der übergeordneten Klasse erweitert und im Fall von $ dieses Schlüsselwort gleich. Sie können auf die nicht statischen Elemente, Methoden und Funktionen einer anderen Klasse zugreifen, wenn diese von der übergeordneten Klasse erweitert werden.

Der unten angegebene Code ist ein Beispiel für self :: und $ this keyword. Kopieren Sie einfach den Code und fügen Sie ihn in Ihre Codedatei ein. Die Ausgabe wird angezeigt.

class cars{
    var $doors=4;   
    static $car_wheel=4;

  public function car_features(){
    echo $this->doors." Doors <br>";
    echo self::$car_wheel." Wheels <br>"; 
  }
}

class spec extends cars{
    function car_spec(){
        print(self::$car_wheel." Doors <br>");
        print($this->doors." Wheels <br>");
    }
}

/********Parent class output*********/

$car = new cars;
print_r($car->car_features());

echo "------------------------<br>";

/********Extend class from another class output**********/


$car_spec_show=new spec;

print($car_spec_show->car_spec());
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.