2219 Stimmen

Wann sollte ich "self" statt "$this" verwenden?

Was ist in PHP 5 der Unterschied zwischen der Verwendung von self y $this ?

Wann ist was angebracht?

0 Stimmen

Mögliche Duplikate von Neues Selbst vs. neue Statik

1926voto

John Millikin Punkte 190278

Kurze Antwort

Utilisez $this um auf die aktuelle Objekt. Verwenden Sie self um auf den aktuelle Klasse. Mit anderen Worten, verwenden Sie $this->member für nicht-statische Mitglieder, verwenden. self::$member für statische Mitglieder.

Vollständige Antwort

Hier ist ein Beispiel für richtig Verwendung von $this y self für nichtstatische und statische Mitgliedsvariablen:

<?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 falsch Verwendung von $this y self für nichtstatische und statische Mitgliedsvariablen:

<?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 con $this für Mitgliedsfunktionen:

<?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 Unterdrückung polymorphen Verhaltens durch die Verwendung von self für Mitgliedsfunktionen:

<?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() ruft die foo() Memberfunktion des genauen Typs des aktuellen Objekts. Wenn das Objekt von type X ruft sie also auf X::foo() . Wenn das Objekt aus type Y ruft sie Y::foo() . Aber mit self::foo(), X::foo() wird immer aufgerufen.

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

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

765voto

nbeagle Punkte 7599

Das Schlüsselwort self bedeutet NICHT sich lediglich auf die "aktuelle Klasse" beziehen, zumindest nicht in einer Weise, die Sie auf statische Mitglieder einschränkt. Im Zusammenhang mit einem nicht statischen Mitglied, self bietet auch eine Möglichkeit, die vtable zu umgehen ( siehe wiki über vtable ) für das aktuelle Objekt. Genauso wie Sie mit parent::methodName() um die Elternversion einer Funktion aufzurufen, so können Sie self::methodName() um die Implementierung einer Methode der aktuellen Klasse aufzurufen.

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 ausgegeben:

Hallo, ich bin Ludwig der Streber
Auf Wiedersehen von Ludwig dem Menschen

sayHello() verwendet die $this Zeiger, so dass die vtable aufgerufen wird, um die Geek::getTitle() . sayGoodbye() verwendet self::getTitle() , so dass die vtable nicht verwendet wird, und Person::getTitle() genannt wird. In beiden Fällen haben wir es mit der Methode eines instanziierten Objekts zu tun und haben Zugriff auf die $this Zeiger innerhalb der aufgerufenen Funktionen.

490voto

Sqoo Punkte 5137

Nicht verwenden self:: . Verwenden Sie static:: *

Es gibt noch einen weiteren Aspekt des Selbst::, der erwähnenswert ist. Lästig, self:: bezieht sich auf den Geltungsbereich zum Zeitpunkt der Definition, 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 Person::status() sehen wir "Person ist lebendig". Betrachten wir nun, was passiert, wenn wir eine Klasse erstellen, die von dieser erbt:

class Deceased extends Person
{

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

}

Aufruf von Deceased::status() würde man erwarten, "Person ist verstorben" zu sehen. Wir sehen jedoch "Person is alive", da der Bereich die ursprüngliche Methodendefinition enthält, wenn der Aufruf von self::getStatus() definiert wurde.

PHP 5.3 bietet eine Lösung. Die static:: Auflösungsoperator implementiert "späte statische Bindung", was soviel heißt wie, dass er an den Bereich der aufgerufenen Klasse gebunden ist. Ändern Sie die Zeile in status() a static::getStatus() und die Ergebnisse sind das, was man erwarten würde. In älteren PHP-Versionen müssen Sie einen Trick finden, um dies zu tun.

Siehe PHP-Dokumentation

Um die Frage zu beantworten, die nicht gestellt wurde...

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

268voto

ircmaxell Punkte 159431

Um wirklich zu verstehen, worüber wir sprechen, wenn wir über self gegen $this Wir müssen uns tatsächlich mit den konzeptionellen und praktischen Aspekten befassen. Ich habe nicht das Gefühl, dass eine der Antworten dies angemessen tut, also hier ist mein Versuch.

Lassen Sie uns zunächst darüber sprechen, was ein Klasse und ein objet ist.

Klassen und Objekte, konzeptionell

Also, was es a Klasse ? Viele Menschen definieren es als eine Blaupause oder eine Vorlage für ein Objekt. In der Tat, Sie können mehr lesen Über Klassen in PHP hier . Und bis zu einem gewissen Grad ist es das auch 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 in dieser Klasse eine Eigenschaft namens $name und eine Methode (Funktion) namens sayHello() .

Es ist sehr wichtig zu beachten, dass die Klasse ist eine statische Struktur. Das bedeutet, dass die Klasse Person einmal definiert, ist immer und überall gleich.

Ein Objekt hingegen ist ein so genannter Instanz einer Klasse. Das bedeutet, dass wir die "Blaupause" der Klasse nehmen und sie verwenden, um eine dynamische Kopie zu erstellen. Diese Kopie ist nun speziell an die Variable gebunden, in der sie gespeichert ist. Daher können alle Änderungen an einer Instanz ist für diese Instanz lokal.

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

Wir schaffen neue Instanzen einer Klasse mit Hilfe der new Betreiber.

Daher sagen wir, dass eine Klasse eine globale Struktur ist und ein Objekt eine lokale Struktur. Machen Sie sich keine Sorgen über diese komische -> Auf die Syntax werden wir gleich noch eingehen.

Eine weitere Sache, über die wir sprechen sollten, ist, dass wir siehe wenn eine Instanz ein instanceof eine bestimmte Klasse: $bob instanceof Person die einen booleschen Wert zurückgibt, wenn die $bob Instanz wurde unter Verwendung der Person Klasse, oder ein Kind von Person .

Zustand definieren

Gehen wir also ein wenig näher darauf ein, was eine Klasse eigentlich enthält. Es gibt 5 Arten von "Dingen", die eine Klasse enthält:

  1. Eigenschaften - Betrachten Sie diese als Variablen, die jede Instanz enthält.

    class Foo {
        public $bar = 1;
    }
  2. Statische Eigenschaften - Betrachten Sie diese als Variablen, die auf Klassenebene gemeinsam genutzt werden. Das 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 auf Instanzen wirken).

    class Foo {
        public function bar() {}
    }
  4. Statische Methoden - Dies sind Funktionen, die von der gesamten Klasse genutzt werden. Sie tun no auf Instanzen wirken, sondern nur auf die statischen Eigenschaften.

    class Foo {
        public static function bar() {}
    }
  5. Konstanten - Klasse aufgelöste Konstanten. Ich gehe hier nicht weiter in die Tiefe, sondern füge dies nur der Vollständigkeit halber hinzu:

    class Foo {
        const BAR = 1;
    }

Im Grunde speichern wir also Informationen über die Klasse und den Objektcontainer mit Hilfe von "Hints" über statisch die angeben, ob die Informationen gemeinsam genutzt werden (und somit statisch sind) oder nicht (und somit dynamisch sind).

Zustand und Methoden

Innerhalb einer Methode wird die Instanz eines Objekts durch die $this variabel. Der aktuelle Zustand dieses Objekts ist dort zu finden, und das Ändern einer Eigenschaft führt zu einer Änderung dieser Instanz (aber nicht anderer).

Wenn eine Methode statisch aufgerufen wird, wird die $this variabel ist nicht definiert . Das liegt daran, dass mit einem statischen Aufruf keine Instanz verbunden ist.

Interessant ist hier, wie statische Aufrufe gemacht werden. Lassen Sie uns also darüber sprechen, wie wir auf den Status zugreifen:

Zugriff auf den Status

Da wir diesen Zustand nun gespeichert haben, müssen wir darauf zugreifen. Das kann ein bisschen knifflig werden (oder Weg mehr als nur ein bisschen), also lassen Sie uns dies in zwei Gesichtspunkte aufteilen: von außerhalb einer Instanz/Klasse (z.B. durch einen normalen Funktionsaufruf oder aus dem globalen Bereich) und innerhalb einer Instanz/Klasse (innerhalb einer Methode auf dem Objekt).

Von außerhalb einer Instanz/Klasse

Von der Außenseite einer Instanz/Klasse aus gesehen sind unsere Regeln recht einfach und vorhersehbar. Wir haben zwei Operatoren, und jeder sagt uns sofort, ob wir es mit einer Instanz oder einer statischen Klasse zu tun haben:

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

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

    Es ist wichtig zu beachten, dass der Aufruf von Person->foo ist nicht sinnvoll (da Person ist eine Klasse, keine Instanz). Daher ist dies ein Parse-Fehler.

  • :: - scope-resolution-operator - Dies wird immer verwendet, um auf eine statische Eigenschaft oder Methode der Klasse zuzugreifen.

    echo Foo::bar()

    Außerdem können wir auf dieselbe Weise eine statische Methode für ein Objekt aufrufen:

    echo $foo::bar()

    Es ist extrem Es ist wichtig zu beachten, dass, wenn wir dies tun von außerhalb wird die Instanz des Objekts vor der bar() Methode. Das heißt, es ist genau dasselbe wie beim Laufen:

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

Deshalb, $this ist in dem statischen Aufruf nicht definiert.

Von innerhalb einer Instanz/Klasse

Die Dinge ändern sich hier ein wenig. Es werden zwar dieselben Operatoren verwendet, aber ihre Bedeutung wird deutlich unschärfer.

El Objekt-Operator -> wird weiterhin verwendet, um den Instanzstatus des Objekts aufzurufen.

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

Aufrufen der bar() Methode auf $foo (ein Fall von Foo ) unter Verwendung des Objekt-Operators: $foo->bar() führt dazu, dass die Version der Instanz von $a .

Das ist also unsere Erwartung.

Die Bedeutung der :: Betreiber aber ändert. Es hängt vom Kontext des Aufrufs der aktuellen Funktion ab:

  • In einem statischen Kontext

    In einem statischen Kontext werden alle Aufrufe, die mit :: wird ebenfalls statisch sein. Schauen wir uns ein Beispiel an:

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

    Aufruf von Foo::bar() ruft die baz() Methode statisch, und daher $this wird no bevölkert werden. Es ist erwähnenswert, dass dies in neueren Versionen von PHP (5.3+) ein E_STRICT Fehler, weil wir nicht-statische Methoden statisch aufrufen.

  • Innerhalb eines Instanzkontextes

    Innerhalb eines Instanzkontextes hingegen werden die Aufrufe, die mit :: hängen vom Empfänger des Aufrufs ab (der Methode, die wir aufrufen). Wenn die Methode definiert ist als static , dann wird ein statischer Aufruf verwendet. Ist dies nicht der Fall, wird die Instanzinformation weitergeleitet.

    Betrachtet man also den obigen Code, so ist der Aufruf von $foo->bar() wird zurückgegeben true da der "statische" Aufruf innerhalb eines Instanzkontexts erfolgt.

Macht das Sinn? Dachte ich nicht. Es ist verwirrend.

Abkürzungsschlüsselwörter

Da es ziemlich unsauber ist, alles mit Klassennamen zu verknüpfen, bietet PHP 3 grundlegende "Abkürzungs"-Schlüsselwörter, um die Bereichsauflösung zu erleichtern.

  • self - Dies bezieht sich auf den aktuellen Klassennamen. Also self::baz() ist dasselbe wie Foo::baz() innerhalb der Foo Klasse (jede Methode davon).

  • parent - Dies bezieht sich auf den Elternteil der aktuellen Klasse.

  • static - Dies bezieht sich auf die aufgerufene Klasse. Dank der Vererbung können untergeordnete Klassen Methoden und statische Eigenschaften außer Kraft setzen. Der Aufruf dieser Klassen mit static anstelle eines Klassennamens ermöglicht es uns, den Ursprung des Aufrufs und nicht die aktuelle Ebene zu ermitteln.

Beispiele

Der einfachste Weg, dies zu verstehen, ist, 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();
    }
}

Hier geht es auch um die Vererbung. Ignorieren Sie für einen Moment, dass dies ein schlechtes Objektmodell ist, aber lassen Sie uns sehen, 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 Kindern gemeinsam genutzt (da wir die self um darauf zuzugreifen. Wenn wir static kann in einer untergeordneten Klasse überschrieben werden).

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

Beachten Sie, dass wir die Person::getName() Instanz Methode jedes Mal. Aber wir verwenden die parent::getName() in einem der Fälle (dem Fall des Kindes) zu tun. Das ist es, was diesen Ansatz so leistungsfähig macht.

Vorsichtshinweis 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 wirklich seltsam hier. Wir rufen eine andere Klasse auf, aber die $this die an den Foo::isFoo() Methode ist die Instanz von $bar .

Dies kann alle Arten von Fehlern und konzeptionellem WTF-ery verursachen. Ich würde also dringend empfehlen, die :: Operator innerhalb von Instanzmethoden auf alles außer diesen drei virtuellen "Abkürzungs"-Schlüsselwörtern ( static , self und parent ).

Vorsichtshinweis Nr. 2

Beachten Sie, dass statische Methoden und Eigenschaften von allen gemeinsam genutzt werden. Das macht sie im Grunde zu globalen Variablen. Mit all den gleichen Problemen, die mit globalen Variablen einhergehen. Ich würde also wirklich zögern, Informationen in statischen Methoden/Eigenschaften zu speichern, es sei denn, Sie fühlen sich wohl damit, dass sie wirklich global sind.

Vorsichtshinweis Nr. 3

Im Allgemeinen sollten Sie das so genannte Late-Static-Binding verwenden, indem Sie static anstelle von self . Es ist jedoch zu beachten, dass dies nicht dasselbe ist, so dass die Aussage "immer static anstelle von self ist wirklich kurzsichtig. Halten Sie stattdessen inne und denken Sie über den Aufruf nach, den Sie machen wollen, und überlegen Sie, ob Sie möchten, dass untergeordnete Klassen diesen Aufruf außer Kraft setzen können statisch aufgelöst anrufen.

TL/DR

Schade, gehen Sie zurück und lesen Sie es. Er mag zu lang sein, aber er ist so lang, weil es ein komplexes Thema ist

TL/DR #2

Okay, gut. Kurz und gut, self wird verwendet, um auf der aktuelle Klassenname innerhalb einer Klasse, während $this bezieht sich auf das aktuelle Objekt Instanz . Beachten Sie, dass self ist eine Abkürzung für das Kopieren/Einfügen. Sie können ihn getrost durch Ihren Klassennamen ersetzen, und es wird funktionieren. Aber $this ist eine dynamische Variable, die nicht im Voraus festgelegt werden kann (und möglicherweise nicht einmal Ihre Klasse ist).

TL/DR #3

Wenn der Objekt-Operator verwendet wird ( -> ), dann müssen Sie immer Sie wissen, dass Sie es mit einer Instanz zu tun haben. Wenn der Scope-Resolution-Operator verwendet wird ( :: ), benötigen Sie weitere Informationen über den Kontext (befinden wir uns bereits in einem Objektkontext? Befinden wir uns außerhalb eines Objekts? usw.).

123voto

MrZebra Punkte 11337

self (nicht $self) bezieht sich auf den Typ der Klasse, während $this bezieht sich auf den aktuellen Instanz der Klasse. self ist für die Verwendung in statischen Mitgliedsfunktionen gedacht, um den Zugriff auf statische Mitgliedsvariablen zu ermöglichen. $this wird in nicht-statischen Mitgliedsfunktionen verwendet und ist ein Verweis auf die Instanz der Klasse, in der die Mitgliedsfunktion aufgerufen wurde.

Denn this ein Objekt ist, verwenden Sie es wie: $this->member

Denn self ist kein Objekt, sondern im Grunde ein Typ, der automatisch auf die aktuelle Klasse verweist. Sie verwenden ihn wie: self::member

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X