Kiedy używać self over $ this?


Odpowiedzi:


1727

Krótka odpowiedź

Użyj, $thisaby odnieść się do bieżącego obiektu. Użyj, selfaby odnieść się do bieżącej klasy. Innymi słowy, użyj $this->memberdla elementów niestatycznych, użyj self::$memberdla elementów statycznych.

Pełna odpowiedź

Oto przykład poprawnego użycia $thisi selfdla niestatycznych i statycznych zmiennych składowych:

<?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();
?>

Oto przykład nieprawidłowego użycia $thisi selfdla niestatycznych i statycznych zmiennych składowych:

<?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();
?>

Oto przykład polimorfizmu ze $thisdla funkcji składowych:

<?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();
?>

Oto przykład tłumienia zachowania polimorficznego przy użyciu selffunkcji składowych:

<?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();
?>

Chodzi o to, że $this->foo()wywołuje foo()funkcję członka niezależnie od dokładnego typu bieżącego obiektu. Jeśli obiekt jest type X, to wywołuje X::foo(). Jeśli obiekt jest type Y, wywołuje Y::foo(). Ale z self :: foo () X::foo()jest zawsze wywoływane.

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

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


330
Ta odpowiedź jest zbyt uproszczona. Jak wskazano w innych odpowiedziach, selfjest używany z operatorem rozdzielczości zakresu ::w odniesieniu do bieżącej klasy; można to zrobić zarówno w kontekście statycznym, jak i niestatycznym. Ponadto jest całkowicie legalne, aby $thiswywoływać metody statyczne (ale nie do pól referencyjnych).
Artefacto,

50
Rozważ także użycie static :: zamiast :: self, jeśli korzystasz z wersji 5.3+. W przeciwnym razie może to powodować niezliczone bóle głowy, zobacz moją odpowiedź poniżej, dlaczego.
Sqoo,

25
-1. Ta odpowiedź jest myląca, przeczytaj pozostałe odpowiedzi, aby uzyskać więcej informacji.
Pacerier

6
Może to być nadmiernie uproszczone, ale odpowiadało na moje podstawowe pytanie, nie powodując wybuchu mojej głowy. Dostałem trochę więcej informacji, które uważałem za pomocne w dalszej części, ale na razie próbowałem po prostu dowiedzieć się, dlaczego trafiłem w moje atrybuty klasy za pomocą $ this-> attrib, a stałe klasy za pomocą self :: constant. Pomogło mi to zrozumieć
MydKnight,

Co $this::?
James

742

Słowo kluczowe self NIE odnosi się tylko do „bieżącej klasy”, a przynajmniej nie w sposób, który ogranicza cię do elementów statycznych. W kontekście elementu niestatycznego selfzapewnia również sposób na ominięcie vtable ( patrz wiki na vtable ) dla bieżącego obiektu. Tak jak możesz użyć parent::methodName()do wywołania rodzicielskiej wersji funkcji, możesz self::methodName()także wywołać bieżącą implementację klasy metody.

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();

Spowoduje to:

Cześć, jestem Ludwig maniakiem
Żegnaj Ludwig od osoby

sayHello()używa $thiswskaźnika, więc vtable jest wywoływany do wywołania Geek::getTitle(). sayGoodbye()używa self::getTitle(), więc vtable nie jest używane i Person::getTitle()jest wywoływane. W obu przypadkach mamy do czynienia z metodą instancji obiektu i mamy dostęp do $thiswskaźnika w ramach wywoływanych funkcji.


3
Ta odpowiedź byłaby jeszcze lepsza, gdybyś zaczął od ogólnej reguły zamiast wyjątku. To kwestia stylu, a nie wiedzy technicznej. To najlepszy przykład, jaki kiedykolwiek widziałem na temat różnicy między self :: a $ this->, ale wstydem jest ukrywać to, najpierw obalając pojęcie.
adjwilli

3
@adjwilli: Dlaczego ten zły styl? Czy to nie podnosi świadomości, że oczekiwanie (teza) PO jest najpierw odrzucone (antyteza), a następnie wyjaśnienie jest podane jako synteza?
hakre

1
Uważam, że „obecna klasa” jest naprawdę problematyczna. Ponieważ tę kombinację słów można rozumieć zarówno jako „klasę, w której się selfznajduje” / „definicję klasy, jest ona dosłowną częścią”, jak również „klasę obiektu” (która w rzeczywistości byłaby static).
Jakumi

Co $this::?
James

1
@James - nie ma dobrego powodu, aby używać $this::; wszystkie możliwe przypadki są już objęte częściej stosowanymi składniami. W zależności od tego, co masz na myśli, stosowanie $this->, self::lub static::.
ToolmakerSteve

461

NIE UŻYWAJ self::, używajstatic::

Jest jeszcze jeden aspekt self ::, o którym warto wspomnieć. Irytująco self::odnosi się do zakresu w punkcie definicji, a nie w miejscu wykonania . Rozważ tę prostą klasę za pomocą dwóch metod:

class Person
{

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

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

}

Jeśli zadzwonimy Person::status(), zobaczymy „Osoba żyje”. Zastanówmy się teraz, co się stanie, gdy stworzymy klasę, która odziedziczy po tym:

class Deceased extends Person
{

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

}

Wywołanie Deceased::status()oczekiwałoby, że zobaczymy „Osoba nie żyje”, ale widzimy, że „Osoba żyje”, ponieważ zakres zawiera oryginalną definicję metody, gdy zdefiniowano wywołanie self::getStatus().

PHP 5.3 ma rozwiązanie. te static::narzędzia operator rozdzielczości „wiązanie późne statyczne”, który to sposób fantazyjny mówić, że to wiąże się z zakresem klasy nazwie. Zmień linię status()na, static::getStatus()a wyniki będą zgodne z oczekiwaniami. W starszych wersjach PHP musisz znaleźć kludge, aby to zrobić.

Zobacz dokumentację PHP

Aby odpowiedzieć na pytanie, które nie zostało zadane ...

$this->odnosi się do bieżącego obiektu (instancji klasy), podczas gdy static::odnosi się do klasy


6
Co z stałymi klasowymi?
Kevin Bond

53
„Calling Deceased :: status () spodziewalibyśmy się, że„ Person is Dead ””. Nie. To jest wywołanie funkcji statycznej, więc nie ma w tym udziału polimorfizm.
cquezel

2
Ze wszystkich wad PHP, nie sądzę, żeby to było w ogóle szaleństwo. W jaki inny sposób pozwolą programistom na oznaczanie metod dla bieżącej klasy (w przeciwieństwie do wyszukiwania ich w vtable)? Gdyby nazwali go inaczej (być może z wiodącymi podkreśleniami), ludzie, którzy chcą tej funkcji, skrytykowaliby ją za brzydkość. W przeciwnym razie, jakikolwiek rozsądny wyraz, którego mogliby użyć, wydaje się, że zawsze łatwo byłoby pomylić ludzi, którzy krytykowaliby go za „szalone” zachowanie, prawdopodobnie nieświadome tego, jak działa metoda wysyłania.
tne

2
Przykład wydaje mi się mylący: widzę getStatusmetodę jako taką, którą wywołałbym dla instancji klasy, a nie dla klasy.
Jānis Elmeris,

1
@Sqoo - powiedzenie „NIE UŻYWAJ self ::, użyj static ::” to dziwny punkt do zrobienia - celowo nie są to te same operacje. Wydaje mi się, że tak naprawdę chodzi o to, aby „było wyraźniej, gdybyś użył rzeczywistej nazwy klasy„ MyClass :: ”, a nie„ self :: ” . Oznacza to, że jeśli chcesz się zachowywać self::, możesz uzyskać to mniej myląco, używając konkretnej nazwy klasy, np MyClass::.
ToolmakerSteve

248

Aby naprawdę zrozumieć, o czym mówimy, gdy mówimy o selfkontra $this, musimy naprawdę zagłębić się w to, co dzieje się na poziomie koncepcyjnym i praktycznym. Nie wydaje mi się, żeby żadna z odpowiedzi zrobiła to odpowiednio, więc oto moja próba.

Zacznijmy od rozmowy o tym, czym jest klasa i obiekt .

Klasy i przedmioty, koncepcyjnie

Więc, co jest klasa ? Wiele osób definiuje go jako plan lub szablon obiektu. Możesz przeczytać więcej o klasach w PHP tutaj . I do pewnego stopnia tak naprawdę jest. Spójrzmy na klasę:

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

Jak widać, w tej klasie jest wywołana właściwość $namei wywołana metoda (funkcja) sayHello().

To bardzo ważne, aby pamiętać, że klasa jest strukturą statyczną. Co oznacza, że Personraz zdefiniowana klasa jest zawsze taka sama wszędzie tam, gdzie na nią spojrzysz.

Natomiast obiekt to tak zwana instancja klasy. Oznacza to, że bierzemy „plan” klasy i używamy go do wykonania dynamicznej kopii. Ta kopia jest teraz ściśle powiązana ze zmienną, w której jest przechowywana. Dlatego wszelkie zmiany w instancji są lokalne dla tej instancji.

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

Tworzymy nowe wystąpienia klasy za pomocą newoperatora.

Dlatego mówimy, że Klasa jest strukturą globalną, a Obiekt jest strukturą lokalną. Nie martw się tą zabawną ->składnią, zajmiemy się nią za chwilę.

Kolejną rzeczą, o której powinniśmy porozmawiać, jest to, że możemy sprawdzić, czy instancja jest instanceofokreśloną klasą: $bob instanceof Personktóra zwraca wartość logiczną, jeśli $bobinstancja została wykonana przy użyciu Personklasy, lub elementu potomnego Person.

Definiowanie stanu

Zobaczmy więc, co tak naprawdę zawiera klasa. Istnieje 5 rodzajów „rzeczy”, które zawiera klasa:

  1. Właściwości - traktuj je jako zmienne, które będzie zawierać każda instancja.

    class Foo {
        public $bar = 1;
    }
  2. Właściwości statyczne - Pomyśl o nich jak o zmiennych, które są współużytkowane na poziomie klasy. Oznacza to, że nigdy nie są kopiowane przez każdą instancję.

    class Foo {
        public static $bar = 1;
    }
  3. Metody - są to funkcje, które każda instancja będzie zawierała (i działała na instancjach).

    class Foo {
        public function bar() {}
    }
  4. Metody statyczne - są to funkcje wspólne dla całej klasy. Oni nie działają w przypadkach, lecz tylko na właściwości statycznych.

    class Foo {
        public static function bar() {}
    }
  5. Stałe - stałe klasowe. Nie wchodzę tutaj głębiej, ale dodajemy dla kompletności:

    class Foo {
        const BAR = 1;
    }

Zasadniczo przechowujemy informacje na temat kontenera klasy i obiektu za pomocą „wskazówek” o statyce, które określają, czy informacja jest współdzielona (a więc statyczna), czy nie (a więc dynamiczna).

Stan i metody

Wewnątrz metody instancja obiektu jest reprezentowana przez $thiszmienną. Obecny stan tego obiektu już istnieje, a mutacja (zmiana) dowolnej właściwości spowoduje zmianę tego wystąpienia (ale nie innych).

Jeśli metoda jest wywoływana statycznie, $thiszmienna nie jest zdefiniowana . Jest tak, ponieważ nie ma instancji powiązanej z wywołaniem statycznym.

Interesującą rzeczą jest tutaj sposób wykonywania połączeń statycznych. Porozmawiajmy więc o tym, w jaki sposób uzyskujemy dostęp do stanu:

Państwo przystępujące

Teraz, kiedy już zapisaliśmy ten stan, musimy uzyskać do niego dostęp. Może to być nieco trudne (lub o wiele więcej), dlatego podzielmy to na dwa punkty widzenia: spoza instancji / klasy (powiedzmy z normalnego wywołania funkcji lub z zakresu globalnego) i wewnątrz instancji / class (z metody na obiekcie).

Z zewnątrz wystąpienia / klasy

Z zewnątrz instancji / klasy nasze zasady są dość proste i przewidywalne. Mamy dwóch operatorów i każdy z nas natychmiast informuje nas, jeśli mamy do czynienia z instancją lub statyczną klasą:

  • ->- operator obiektu - jest zawsze używany, gdy uzyskujemy dostęp do instancji.

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

    Ważne jest, aby pamiętać, że wywoływanie Person->foonie ma sensu (ponieważ Personjest klasą, a nie instancją). Dlatego jest to błąd analizy.

  • ::- operator-rozdzielczości-zakresu - zawsze służy do uzyskania dostępu do właściwości lub metody statycznej klasy.

    echo Foo::bar()

    Dodatkowo możemy wywołać metodę statyczną na obiekcie w ten sam sposób:

    echo $foo::bar()

    Jest to niezwykle ważne, aby pamiętać, że gdy robimy to z zewnątrz , instancja obiektu jest ukryte przed bar()metody. Oznacza to, że jest to dokładnie to samo, co bieganie:

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

Dlatego $thisnie jest zdefiniowany w wywołaniu statycznym.

From Inside Of Instance / Class

Tutaj coś się trochę zmienia. Używane są te same operatory, ale ich znaczenie staje się znacznie rozmyte.

Operator obiektu -> jest nadal używany do wywoływania stanu instancji obiektu.

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

Wywołanie bar()metody $foo(instancja Foo) przy użyciu operatora obiektu: $foo->bar()spowoduje utworzenie wersji instancji $a.

Tak właśnie się spodziewamy.

Znaczenie ::operatora zmienia się. Zależy to od kontekstu wywołania bieżącej funkcji:

  • W kontekście statycznym

    W kontekście statycznym wszelkie wywołania wykonane przy użyciu ::będą również statyczne. Spójrzmy na przykład:

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

    Wywołanie Foo::bar()wywoła baz()metodę statycznie, a więc $thisbędzie nie być wypełniane. Warto zauważyć, że w najnowszych wersjach PHP (5.3+) spowoduje to E_STRICTbłąd, ponieważ statycznie nazywamy metody niestatyczne.

  • W kontekście instancji

    Z drugiej strony, w kontekście wystąpienia, wywołania wykonane ::zależą od odbiorcy wywołania (metody, którą wywołujemy). Jeśli metoda jest zdefiniowana jako static, wówczas użyje wywołania statycznego. Jeśli nie, prześle informacje o instancji.

    Tak więc, patrząc na powyższy kod, wywołanie $foo->bar()powróci true, ponieważ wywołanie „statyczne” odbywa się w kontekście instancji.

Ma sens? Tak nie myślałem. To jest mylące.

Skrótowe słowa kluczowe

Ponieważ wiązanie wszystkiego za pomocą nazw klas jest raczej brudne, PHP udostępnia 3 podstawowe słowa kluczowe „skrótowe”, aby ułatwić rozwiązywanie zakresu.

  • self- Odnosi się do bieżącej nazwy klasy. Tak self::baz()samo jest Foo::baz()w Fooklasie (dowolna metoda).

  • parent - Odnosi się do rodzica bieżącej klasy.

  • static- Odnosi się to do wywoływanej klasy. Dzięki dziedziczeniu klasy potomne mogą zastępować metody i właściwości statyczne. Wywołanie ich przy użyciu staticzamiast nazwy klasy pozwala nam ustalić, skąd pochodzi połączenie, a nie na bieżącym poziomie.

Przykłady

Najłatwiej to zrozumieć, zaczynając od kilku przykładów. Wybierzmy klasę:

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();
    }
}

Teraz przyglądamy się również dziedziczeniu. Zignoruj ​​przez chwilę, że jest to zły model obiektowy, ale spójrzmy na to, co się stanie, gdy będziemy się z tym bawić:

$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

Licznik identyfikatorów jest więc współużytkowany przez obie instancje i dzieci (ponieważ korzystamy selfz niego, aby uzyskać do niego dostęp. Gdybyśmy korzystali static, moglibyśmy zastąpić go w klasie potomnej).

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

Pamiętaj, że za każdym razem wykonujemy metodę Person::getName() instancji . Ale używamy parent::getName()do tego w jednym z przypadków (przypadek podrzędny). To sprawia, że ​​to podejście jest potężne.

Słowo ostrzeżenia # 1

Zauważ, że kontekst wywołania określa, czy instancja jest używana. W związku z tym:

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

Nie zawsze jest to prawda.

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

Teraz jest tu naprawdę dziwnie. Wzywamy inną klasę, ale metoda $thisprzekazywana do Foo::isFoo()metody jest instancją klasy $bar.

Może to powodować różnego rodzaju błędy i koncepcyjne WTF. Więc ja bardzo sugerują unikanie ::operatora od wewnątrz metody instancji na wszystko z wyjątkiem tych trzech wirtualnych „short-cut” (słowa kluczowe static, selfi parent).

Słowo ostrzeżenia # 2

Pamiętaj, że wszystkie metody i właściwości statyczne są wspólne. To czyni je zasadniczo zmiennymi globalnymi. Z tymi samymi problemami, które występują w globalsach. Byłbym więc bardzo niezdecydowany, aby przechowywać informacje w statycznych metodach / właściwościach, chyba że czujesz się swobodnie, ponieważ jest to prawdziwie globalne.

Słowo ostrzeżenia # 3

Ogólnie rzecz biorąc, będziesz chciał użyć tak zwanego późnego wiązania statycznego, używając staticzamiast self. Pamiętaj jednak, że to nie to samo, dlatego powiedzenie „zawsze używaj staticzamiast zamiast selfjest naprawdę krótkowzroczne. Zamiast tego zatrzymaj się i pomyśl o połączeniu, które chcesz wykonać, i pomyśl, czy chcesz, aby klasy potomne mogły zastąpić to rozwiązanie statyczne połączenie.

TL / DR

Szkoda, wróć i przeczytaj. To może być za długie, ale tak długo, ponieważ jest to złożony temat

TL / DR # 2

Ok dobrze. W skrócie, selfsłuży do odwołania do bieżącej nazwy klasy w klasie, gdzie $thisodnosi się do bieżącej instancji obiektu . Pamiętaj, że selfjest to skrót do kopiowania / wklejania. Możesz go bezpiecznie zastąpić nazwą klasy i będzie dobrze działać. Ale $thisjest zmienną dynamiczną, której nie można ustalić z wyprzedzeniem (i może nawet nie być twoją klasą).

TL / DR # 3

Jeśli używany jest operator obiektu ( ->), zawsze wiesz, że masz do czynienia z instancją. Jeśli używany jest operator rozpoznawania zakresu ( ::), potrzebujesz więcej informacji o kontekście (czy już jesteśmy w kontekście obiektowym? Czy jesteśmy poza obiektem? Itp.).


1
Słowo ostrzeżenia # 1: $ to nie zostanie zdefiniowane podczas wywoływania metody statycznej: 3v4l.org/9kr0e
Mark Achée

Cóż ... $thisnie zostanie zdefiniowany, jeśli będziesz przestrzegać „ścisłych standardów” i nie wywołasz metod statycznie, które nie są zdefiniowane jako statyczne. Widzę wynik, który wyjaśniłeś tutaj: 3v4l.org/WeHVM Zgoda, naprawdę dziwne.
Mark Achée

2
Po całkowitym przeczytaniu długiego opisu poczułem lenistwo, aby przewinąć go ponownie, aby go głosować. Tylko żartowałem, głosowałem za tym: D. Dzięki, to jest bardzo przydatne.
Mr_Green

3
dobrze byłoby dodać jasne wyjaśnienie różnicy między self :: $ property a self :: property; Myślę, że to też jest dość mylące
Tommaso Barbugli

1
WoC # 1 zachowuje się inaczej niż PHP 7. Jak Foo::isFoo()to się nazywa statycznie, $thisnie zostanie zdefiniowane. To moim zdaniem bardziej intuicyjne zachowanie. - Podaje się inny wynik, jeśli Barmiałby zostać przedłużony Foo. Wtedy wywołanie Foo::isFoo()byłoby w rzeczywistości w kontekście instancji (nie jest specyficzne dla PHP7).
Kontrollfreak

117

self(nie $ self) odnosi się do typu klasy, gdzie $thisodnosi się do bieżącej instancji klasy. selfjest przeznaczony do użycia w statycznych funkcjach członka, aby umożliwić ci dostęp do statycznych zmiennych członka. $thisjest używany w niestatycznych funkcjach składowych i jest odwołaniem do instancji klasy, w której wywołano funkcję składową.

Ponieważ thisjest to obiekt, używasz go w następujący sposób:$this->member

Ponieważ selfnie jest obiektem, jest to po prostu typ, który automatycznie odnosi się do bieżącej klasy, używasz go w następujący sposób:self::member


97

$this-> jest używany w odniesieniu do określonego wystąpienia zmiennych klasy (zmiennych składowych) lub metod.

Example: 
$derek = new Person();

$ derek jest teraz specyficzną instancją Osoby. Każda osoba ma imię i nazwisko, ale $ derek ma określone imię i nazwisko (Derek Martin). Wewnątrz instancji $ derek możemy nazywać ją $ ​​this-> first_name i $ this-> last_name

KlasaNazwa :: jest używana w odniesieniu do tego typu klasy i jej zmiennych statycznych, metod statycznych. Jeśli to pomoże, możesz mentalnie zastąpić słowo „statyczny” słowem „udostępniony”. Ponieważ są udostępnione, nie mogą odnosić się do $ this, który odnosi się do konkretnej instancji (nieudostępnionej). Zmienne statyczne (tj. Static $ db_connection) mogą być współużytkowane przez wszystkie instancje typu obiektu. Na przykład wszystkie obiekty bazy danych dzielą jedno połączenie (połączenie statyczne $).

Zmienne statyczne Przykład: Udawaj, że mamy klasę bazy danych z jedną zmienną składową: static $ num_connections; Teraz wstaw to do konstruktora:

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

Podobnie jak obiekty mają konstruktory, mają także destruktory, które są wykonywane, gdy obiekt umiera lub jest rozbrojony:

function __destruct()
{
    $num_connections--;
}

Za każdym razem, gdy tworzymy nową instancję, zwiększy ona licznik połączeń o jeden. Za każdym razem, gdy niszczymy lub przestajemy używać instancji, zmniejsza ona licznik połączeń o jeden. W ten sposób możemy monitorować liczbę instancji obiektu bazy danych, którego używamy z:

echo DB::num_connections;

Ponieważ $ num_connections jest statyczny (współdzielony), będzie odzwierciedlał całkowitą liczbę aktywnych obiektów bazy danych. Być może widziałeś tę technikę używaną do współdzielenia połączeń z bazą danych między wszystkimi instancjami klasy bazy danych. Dzieje się tak, ponieważ tworzenie połączenia z bazą danych zajmuje dużo czasu, dlatego najlepiej utworzyć tylko jedno i udostępnić je (nazywa się to Wzorem Singletona).

Metody statyczne (tj. Publiczny widok statyczny :: numer_format_pliku (cyfry $)) mogą być używane BEZ pierwszej instancji jednego z tych obiektów (tzn. Nie odnoszą się wewnętrznie do $ this).

Przykład metody statycznej:

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

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

Jak widać, publiczna funkcja statyczna prettyName nie wie nic o obiekcie. Po prostu działa z parametrami, które przekazujesz, jak normalna funkcja, która nie jest częścią obiektu. Po co więc zawracać sobie głowę, skoro nie moglibyśmy mieć go jako przedmiotu?

  1. Po pierwsze, dołączanie funkcji do obiektów pomaga utrzymać porządek, dzięki czemu wiesz, gdzie je znaleźć.
  2. Po drugie, zapobiega konfliktom nazw. W dużym projekcie prawdopodobnie dwóch programistów utworzy funkcje getName (). Jeśli jeden tworzy ClassName1 :: getName (), a drugi tworzy ClassName2 :: getName (), nie stanowi to żadnego problemu. Bez konfliktu. Metody statyczne!

SELF :: Jeśli kodujesz poza obiektem, który ma metodę statyczną, do której chcesz się odwoływać, musisz wywołać go przy użyciu nazwy obiektu View :: format_phone_number ($ phone_number); Jeśli kodowanie wewnątrz obiektu, który ma metodę statyczną chcesz zwrócić, można też korzystać z obiektu nazwa widoku :: format_phone_number ($ PN) lub można użyć self :: $ format_phone_number (PN) skrót

To samo dotyczy zmiennych statycznych: Przykład: View :: templates_path vs. self :: templates_path

Wewnątrz klasy DB, gdybyśmy odwoływali się do metody statycznej jakiegoś innego obiektu, użylibyśmy nazwy obiektu: Przykład: Session :: getUsersOnline ();

Ale gdyby klasa DB chciała odwoływać się do własnej zmiennej statycznej, powiedziałaby po prostu self: Przykład: self :: connection;

Mam nadzieję, że pomoże to wyjaśnić :)


Świetna odpowiedź. Chciałbym tylko podkreślić, że odnosząc się do atrybutu statycznego, musisz użyć $znaku. Na przykładself::$templates_path
henrywright

30

Z tego postu na blogu :

  • self odnosi się do bieżącej klasy
  • self może być używany do wywoływania funkcji statycznych i odwoływania się do statycznych zmiennych składowych
  • self może być używany wewnątrz funkcji statycznych
  • self może także wyłączyć zachowanie polimorficzne, omijając tabelę vt
  • $this odnosi się do bieżącego obiektu
  • $this może być używany do wywoływania funkcji statycznych
  • $thisnie należy używać do wywoływania statycznych zmiennych składowych. Użyj selfzamiast tego.
  • $this nie może być stosowany w funkcjach statycznych

26

W PHP używasz słowa kluczowego self, aby uzyskać dostęp do właściwości i metod statycznych.

Problemem jest to, że można zastąpić $this->method()z self::method()dowolnego miejsca, niezależnie od tego czy method()jest static czy nie. Którego powinieneś użyć?

Rozważ ten kod:

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();

W tym przykładzie self::who()zawsze wyświetli „rodzic”, a $this->who()będzie zależeć od tego, jaką klasę ma obiekt.

Teraz widzimy, że self odnosi się do klasy, w której jest wywoływane, natomiast $thisodnosi się do klasy bieżącego obiektu .

Dlatego powinieneś używać self tylko wtedy, gdy $thisnie jest ono dostępne lub gdy nie chcesz pozwolić klasom potomnym na zastąpienie bieżącej metody.


22

Wewnątrz definicji klasy $thisodnosi się do bieżącego obiektu, a selfodnosi się do bieżącej klasy.

Konieczne jest odwołanie się do elementu klasy za pomocą selfi odniesienia do elementu obiektu za pomocą $this.

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

21

Oto przykład poprawnego użycia $ this i self dla niestatycznych i statycznych zmiennych składowych:

<?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

Według http://www.php.net/manual/en/language.oop5.static.php nie ma $self. Istnieje tylko $thisodniesienie do bieżącej instancji klasy (obiektu) i self, które może służyć do odwoływania się do statycznych elementów klasy. W grę wchodzi tutaj różnica między instancją obiektu a klasą.


9
Sugestia: Przeczytaj tę odpowiedź, gdy potkniesz się na kwas.
a20

16

Uważam, że nie było pytania, czy można wywołać statycznego członka klasy, dzwoniąc ClassName::staticMember. Pytanie brzmiało, jaka jest różnica między używaniem self::classmembera$this->classmember .

Na przykład oba poniższe przykłady działają bezbłędnie, niezależnie od tego, czy używasz, self::czy$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;
    }
}

Szczególnie zabawne jest rozpoczęcie odpowiedzi od „Wierzę, że pytanie nie brzmiało, czy można wywołać statycznego członka klasy, wywołując ClassName :: staticMember. Pytanie dotyczyło różnicy między używaniem self :: classmember a $ this-> classmember” a następnie przejdziecie w ogóle do żadnych różnic. W rzeczywistości pokazujesz przykład, w którym obie opcje działają identycznie. -1
Buttle Butkus

Mimo to przydatne. Zakres dotyczył rozdzielczości i ta część nie jest jasna w podręczniku php. Nadal uważam, że jest to przydatne
renoirb

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

16

self odnosi się do bieżącej klasy (w której się nazywa),

$thisodnosi się do bieżącego obiektu. Możesz użyć statycznego zamiast siebie. Zobacz przykład:

    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();

Wyjście: dziecko nadrzędne


16
  • Wskaźnik obiektu $thisodnosi się do bieżącego obiektu.
  • Wartość klasy staticodnosi się do bieżącego obiektu.
  • Wartość klasy selfodnosi się do dokładnej klasy, w której została zdefiniowana.
  • Wartość klasy parentodnosi się do rodzica dokładnej klasy, w której została zdefiniowana.

Zobacz następujący przykład, który pokazuje przeciążenie.

<?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"

Przez większość czasu chcesz odwoływać się do bieżącej klasy, dlatego używasz staticlub $this. Są jednak chwile, kiedy potrzebujesz, self ponieważ chcesz oryginalnej klasy bez względu na to, co ją rozszerza. (Bardzo, bardzo rzadko)


14

Ponieważ nikt tutaj nie mówił o występach, oto mały test, który zrobiłem (5.6):

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

To są wyniki dla 2 000 000 przebiegów, a oto kod, którego użyłem:

<?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
Wywołanie funkcji braku operacji 2 000 000 razy trwa 1s. Uwielbiam PHP.
rr-

Dobry stary PHP. :) Ale połączenie = 0,001 ms. Jest aż tak źle?
tleb

Wierzę, że to (i podobne rzeczy) powoduje, że rzeczy takie jak ORM są powolne, chyba że buforujesz rzeczy, a statyczne generatory witryn to coś.
rr-

2
Teoretycznie powinien zająć 1 cykl zegara procesora, co sprawia, że ​​w 1 / 2e9 s = 0.5 nstych dniach
Buddy

Po prostu przeczytaj ponownie moją odpowiedź. Uważaj: to także tworzy klasę . Nie wiem, dlaczego nie useużyłem słowa kluczowego tbh, ale nie mam już PHP, aby powtórzyć test porównawczy, i nie mam ochoty go ponownie instalować.
tleb

13

W przypadku selfużycia z ::operatorem odnosi się do bieżącej klasy, co można wykonać zarówno w kontekście statycznym, jak i niestatycznym. $thisodnosi się do samego obiektu. Ponadto całkowicie legalne jest $thiswywoływanie metod statycznych (ale nie odwoływanie się do pól).


8

Natrafiłem na to samo pytanie, a prosta odpowiedź brzmi:

  • $this wymaga wystąpienia klasy
  • self:: nie

Ilekroć używasz metod statycznych lub atrybutów statycznych i chcesz je wywoływać bez tworzenia instancji obiektu klasy, musisz użyć ich self:do wywołania, ponieważ $thiszawsze wymaga utworzenia obiektu.


7

$thisodnosi się do bieżącego obiektu klasy, selfodnosi się do bieżącej klasy (nie obiektu). Klasa jest planem obiektu. Więc definiujesz klasę, ale konstruujesz obiekty.

Innymi słowy, użyj self for statici this for none-static members or methods.

również w scenariuszu podrzędnym / nadrzędnym self / parentstosuje się głównie do identyfikacji członków i metod klas podrzędnych i nadrzędnych.


7

Ponadto, ponieważ $this::nie został jeszcze omówiony.

Wyłącznie w celach informacyjnych, począwszy od PHP 5.3 w przypadku obiektów utworzonych w celu uzyskania bieżącej wartości zakresu, w przeciwieństwie do używania static::, można alternatywnie używać w ten $this::sposób.

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

Użycie powyższego kodu nie jest powszechną ani zalecaną praktyką, ale służy jedynie zilustrowaniu jego użycia i ma charakter bardziej przypominający „Czy wiesz?” w nawiązaniu do pytania oryginalnego plakatu.

Reprezentuje również użycie $object::CONSTANTnpecho $foo::NAME; . W przeciwieństwie do$this::NAME;


5

Użyj, selfjeśli chcesz wywołać metodę klasy bez tworzenia obiektu / instancji tej klasy, oszczędzając w ten sposób pamięć RAM (czasami do tego celu używaj self). Innymi słowy, faktycznie wywołuje metodę statycznie. Użyj thisdo perspektywy obiektu.


2

Przypadek 1: Użyj self może być użyte dla stałych klas

 klasa klasa A { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}

Jeśli chcesz wywołać go poza klasą, użyj, classA::POUNDS_TO_KILOGRAMSaby uzyskać dostęp do stałych

Przypadek 2: Dla właściwości statycznych

klasa klasa C {
     funkcja publiczna __construct () { 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}

1

Według php.net istnieją trzy specjalne słowa kluczowe w tym kontekście: self, parenti static. Służą do uzyskiwania dostępu do właściwości lub metod z definicji klasy.

$thisz drugiej strony służy do wywoływania instancji i metod dowolnej klasy, o ile klasa ta jest dostępna.


-1

 słowo kluczowe :: :: używane dla bieżącej klasy i zasadniczo służy do uzyskiwania dostępu do elementów statycznych, metod i stałych. Ale w przypadku $ nie można wywołać statycznego elementu, metody i funkcji.

Możesz użyć słowa kluczowego self :: w innej klasie i uzyskać dostęp do elementów statycznych, metody i stałych. Kiedy będzie rozszerzany z klasy nadrzędnej i tak samo w przypadku $ tego słowa kluczowego. Możesz uzyskać dostęp do niestatycznych elementów, metody i funkcji w innej klasie, gdy będzie ona rozszerzana z klasy nadrzędnej.

Podany poniżej kod jest przykładem słowa kluczowego self :: i $ . Po prostu skopiuj i wklej kod do pliku kodu i zobacz wynik.

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());
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.