Kada koristiti self over $ this?

U PHP-u 5, koja je razlika između korištenja self i $this ?

Kada se svatko uklapa?

1788
30 сент. Casey Watson 30 od rujna. 2008-09-30 09:23 '08 u 9:23 am 2008-09-30 09:23
@ 22 odgovora

Kratak odgovor

Koristite $this za označavanje trenutnog objekta. Koristite se za označavanje trenutne klase. Drugim riječima, koristite $this->member za ne-statičke elemente, koristite self::$member za statičke elemente.

Puni odgovor

Slijedi primjer korištenja ispravnog $this i self za ne-statičke i statične članske varijable:

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

Slijedi primjer korištenja pogrešnog $this i self za ne-statičke i statične članske varijable:

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

Ovdje je primjer polimorfizma s $this za članske funkcije:

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

Ovdje je primjer suzbijanja polimorfnog ponašanja sa self za članske funkcije:

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

Ideja je da $this->foo() poziva funkciju člana foo() funkcije what> - točnu vrstu trenutnog objekta. Ako objekt ima type X , on tako> poziva X::foo() . Ako objekt ima vrijednost type Y , on poziva Y::foo() . Ali s> self :: foo (), X::foo() uvijek zove.

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

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

1519
30 сент. Odgovor dao John Millikin 30. rujna 2008-09-30 09:29 '08 u 9:29 2008-09-30 09:29

Ključna riječ self se NE odnosi samo na "trenutnu klasu", barem ne na način koji vas ograničava na statične članove. U kontekstu ne-statičnog člana, self također osigurava način za zaobilaženje vtable ( vidi Wiki na vtable ) za trenutni objekt.Kao što možete koristiti parent::methodName() za pozivanje nadređene verzije funkcije, stoga možete nazvati self::methodName() nazvati trenutnu implementaciju metode.

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

To će ispisati:

border=0

Bok, ja sam Ludwig geek
Zbogom Ludwig Man

sayHello() koristi $this pointer, tako da je vtable pozvan da nazove Geek::getTitle() . sayGoodbye() koristi self::getTitle() , tako da se vtable ne koristi i zove se Person::getTitle() . U oba slučaja imamo posla s metodom objekta instance i imamo pristup do $this pokazivača unutar pozvanih funkcija.

712
27 июля '09 в 21:00 2009-07-27 21:00 odgovor je dao nbeagle 27. srpnja 2009. u 21:00 2009-07-27 21:00

NE koristite self:: , koristite static::

Postoji još jedan aspekt sebe: vrijedno je spomenuti. Uznemirujuće, self:: odnosi se na područje u točki definicije, a ne na točku izvršenja . Razmotrite ovu jednostavnu klasu na dva načina:

 class Person { public static function status() { self::getStatus(); } protected static function getStatus() { echo "Person is alive"; } } 

Ako pozovemo Person::status() vidjet ćemo da je "Čovjek živ." Sada razmislite što se događa kada stvorimo klasu koja nasljeđuje ovo:

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

Nazivajući Deceased::status() očekujemo da ćemo vidjeti "Osoba je mrtva", međutim, vidimo da "Osoba je živa" jer područje sadrži definiciju izvorne metode kada je definiran poziv na self::getStatus() .

PHP 5.3 ima rješenje. static:: rezolucijski operator implementira "kasno statično vezanje", što je fancy način da se kaže da je povezan s opsegom klase. Promijenite status() u static::getStatus() i rezultati su ono što očekujete. U starijim verzijama PHP-a trebat ćete pronaći kludge za ovo.

Pogledajte PHP dokumentaciju .

Stoga, odgovoriti na pitanje, a ne na pitanje ...

$this-> odnosi se na trenutni objekt (instanca klase), dok static:: odnosi se na klasu

429
24 июля '11 в 18:08 2011-07-24 18:08 odgovor je dan Sqoo 24. srpnja '11 u 18:08 2011-07-24 18:08

Da bismo doista razumjeli o čemu govorimo kada govorimo o self odnosu na $this , moramo stvarno iskopati ono što se događa na konceptualnoj i praktičnoj razini. Stvarno ne osjećam da bilo koji odgovor odgovara ovome, pa evo mog pokušaja.

Neka razgovor započne s onim što su klasa i objekt.

Klase i objekti, konceptualno

Dakle, što je klasa? Mnogi ga definiraju kao plan ili predložak za objekt. Zapravo, možete pročitati više o PHP klasama ovdje . I do neke mjere to je ono što doista jest. Pogledajte razred:

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

Kao što možete vidjeti, u ovoj klasi nalazi se svojstvo $name i metoda (funkcija) nazvana sayHello() .

Vrlo je važno napomenuti da je klasa statička struktura. To znači da je klasa Person , jednom definirana, uvijek ista kada je pogledate.

S druge strane, objekt se naziva instanca klase. To znači da uzmemo “plan” ove klase i koristimo ga za stvaranje dinamičke kopije. Ova kopija je sada posebno vezana za varijablu u kojoj je pohranjena. Stoga je svaka instancijska promjena lokalna za ovu instancu.

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

Stvaramo nove instance klase pomoću new operatora.

Stoga kažemo da je klasa globalna struktura, a objekt je lokalna struktura. Ne brinite o ovoj smiješnoj sintaksi -> , malo ćemo o tome razgovarati.

Još jedna stvar o kojoj trebamo razgovarati je da možemo provjeriti je li instanca instanceof određena klasa: $bob instanceof Person , koja vraća boolean vrijednost ako je instanca $bob stvorena pomoću klase Person ili dijete elementa ,

Definicija države

Dopustite mi da malo shvatim što razred sadrži. Postoji 5 vrsta "stvari" koje razred sadrži:

  • Svojstva. Razmislite o tome kao o varijablama koje će svaka instanca imati.

     class Foo { public $bar = 1; } 
  • Statička svojstva. Razmislite o tome kao o varijablama koje se dijele na razini razreda. To znači da ih nikada ne kopira svaka kopija.

     class Foo { public static $bar = 1; } 
  • Metode su funkcije koje će svaka instanca sadržavati (i raditi s instancama).

     class Foo { public function bar() {} } 
  • Statičke metode. To su funkcije koje se dijele u cijelom razredu. Oni ne rade, ali umjesto toga vrijede samo statička svojstva.

     class Foo { public static function bar() {} } 
  • Konstante - Konstante razriješenih klasa. Ne ulazite ovdje duboko, nego dodajući za potpunost:

     class Foo { const BAR = 1; } 

Tako pohranjujemo podatke o kontejneru klase i objekta pomoću statičkih savjeta koji određuju je li informacija javno dostupna (i stoga statična) ili ne (i stoga dinamična).

Stanje i metode

Unutar metode, objektna instanca predstavlja $this varijabla. Trenutno stanje ovog objekta postoji, a promjena (promjena) u bilo kojem svojstvu će dovesti do promjene u ovom slučaju (ali ne i kod drugih).

Ako se metoda zove statički, $this varijabla je nedefinirana. To je zbog činjenice da ne postoji instanca povezana sa statičkim pozivom.

Pitam se kako su statični pozivi stvoreni. Razgovarajmo o tome kako pristupamo državi:

Pristup državi

Sada kada smo spasili ovo stanje, moramo mu pristupiti. To može biti pomalo zbunjujuće (ili više od malo), pa ga podijelimo u dvije točke gledišta: izvan instance / klase (recimo, iz normalnog poziva funkcije ili iz globalnog opsega) i unutar instance / klase (iz metode u objektu).

Izvan instance / klase

Izvan instance / klase, naša pravila su prilično jednostavna i predvidljiva. Imamo dvije izjave i svaka nam odmah kaže ako se radi o instanci ili statičkoj klasi:

  • -> - objekt-operator - ovo se uvijek koristi kada pristupamo instanci.

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

    Važno je napomenuti da pozivanje Person->foo nema smisla (budući da je Person klasa, a ne instanca). Stoga je ovo pogreška pri raščlanjivanju.

  • :: - scope-resolution-operator - ovo se uvijek koristi za pristup statičkoj osobini ili metodi klase.

     echo Foo::bar() 

    Osim toga, možemo pozvati statičku metodu za objekt na isti način:

     echo $foo::bar() 

    Vrlo je važno napomenuti da kada to radimo izvana , instanca objekta je skrivena od metode bar() . To znači da je točno isto kao što radi:

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

Stoga, $this nije definirano u statičkom pozivu.

Inside instance / class

Stvari se malo mijenjaju. Koriste se isti operatori, ali njihovo značenje postaje značajno zamagljeno.

Operator objekta -> i dalje se koristi za upućivanje poziva stanju stanja objekta.

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

Pozivanje metode bar() na $foo (primjer Foo ) pomoću objekta operatora: $foo->bar() rezultirat će verzijom instance $a .

Dakle, kao što očekujemo.

Promjena vrijednosti operatora. To ovisi o kontekstu trenutnog poziva funkcije:

  • U statičnom kontekstu

    U statičkom kontekstu, svi pozivi napravljeni sa :: također će biti statični. Razmotrite primjer:

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

    Pozivanje Foo::bar() pozvat će metodu baz() statički, pa će $this biti popunjena ne . Važno je napomenuti da će u novijim verzijama PHP-a (5.3+) doći do E_STRICT pogreške, jer smo statički postavili ne-statičke metode.

  • U kontekstu instance

    U kontekstu instance, s druge strane, pozivi koji koriste :: ovise o primatelju poziva (metoda koju zovemo). Ako je metoda definirana kao static , tada će se koristiti statički poziv. Ako ne, poslat će informacije o instanci.

    Dakle, nakon razmatranja gornjeg koda, poziv na $foo->bar() vraća true , budući da se "statički" poziv javlja u kontekstu instance.

Ima li smisla? Nisam tako mislio. To je zbunjujuće.

Kratkoročne ključne riječi

Budući da je povezivanje svega zajedno pomoću naziva klasa prilično neuredno, PHP nudi 3 osnovne riječi za prečac kako bi se olakšalo rješavanje domene.

  • self - Ovo se odnosi na naziv trenutne klase. Dakle, self::baz() podudara se s Foo::baz() u klasi Foo (bilo koja metoda na njoj).

  • parent - Ovo se odnosi na roditelja trenutne klase.

  • static - Ovo se odnosi na klasu koja se zove. Zbog nasljeđivanja, klase dijete mogu nadjačati metode i statička svojstva. Stoga, pozivanje na static umjesto imena klase omogućuje nam da odredimo odakle je došao poziv, a ne trenutačnu razinu.

primjeri

Najlakši način da to shvatite je da počnete učiti neke primjere. Odaberite klasu:

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

Sada također gledamo na nasljedstvo. Ignorirajte na trenutak da je ovo loš objektni model, ali da vidimo što će se dogoditi kada se s njim igramo:

 $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 

Dakle, ID brojač se koristi za oba slučaja i za djecu (jer mi koristimo ga za pristup. Ako smo koristili static , mogli bismo je redefinirati u podređenoj klasi).

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

Primijetite da svaki put izvršavamo metodu instance od Person::getName() . No, mi koristimo parent::getName() da bismo to učinili u jednom od slučajeva (child register). To je ono što ovaj pristup čini moćnim.

Riječ opreza # 1

Imajte na umu da kontekst pozivanja određuje da li se instanca koristi. Stoga:

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

Nije uvijek točno.

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

Ovo je stvarno čudno. Zovemo drugu klasu, ali $this , koja se prosljeđuje Foo::isFoo() metodi, je instanca $bar .

To može uzrokovati sve vrste pogrešaka i konceptualnog WTF-a. Stoga, izričito preporučujem izbjegavanje :: operator iz primjera metoda na sve osim tri virtualne "kratke" ključne riječi ( static , self i parent ).

Riječ upozorenja # 2

Imajte na umu da statičke metode i svojstva dijele svi. To ih čini uglavnom globalnim varijablama. Sa svim istim problemima kao globalni. Stoga bih bio vrlo nesposoban pohranjivati ​​informacije u statičkim metodama / svojstvima, ako vam se ne sviđa, to je stvarno globalno.

Riječ upozorenja broj 3

Općenito, htjet ćete koristiti ono što je poznato kao kasno-statičko vezanje, koristeći static umjesto self . Ali imajte na umu da to nije ista stvar, tako da je "uvijek upotreba static umjesto self stvarno kratkovidna. Umjesto toga, zaustavite se i razmislite o pozivu koji želite napraviti i razmislite o tome želite li da dječje klase mogu nadjačati ovaj statični dopušteni poziv

Tl / dr

Šteta, vratite se i čitajte. Možda je predugačak, ali je tako dugačak jer je to teška tema.

TL / DR # 2

Dobro, super. Ukratko, self koristi za upućivanje na trenutno ime klase u klasi, gdje se $this odnosi na trenutnu instancu objekta. Imajte na umu da je self copy / paste. Možete ga sigurno zamijeniti nazivom svoje klase i to će dobro funkcionirati. Ali $this je dinamička varijabla koja ne može biti unaprijed definirana (a možda i nije vaša klasa).

TL / DR # 3

Ako koristite operator objekta ( -> ), uvijek znate da imate posla s instancom. Ako koristite operatora rezolucije ( :: , potrebne su vam dodatne informacije o kontekstu (jesmo li već u kontekstu objekta? Jesmo li izvan objekta? Itd.).

229
10 июня '13 в 18:21 2013-06-10 18:21 odgovor je dat ircmaxell 10. lipnja '13 u 18:21 2013-06-10 18:21

self (not $ self) se odnosi na tip klase, gdje $this odnosi na trenutnu instancu klase. self namijenjen za korištenje u statičkim članskim funkcijama, tako da možete pristupiti statičkim članskim varijablama. $this koristi u ne-statičkim članskim funkcijama i odnosi se na instancu klase kojoj je pozvana funkcija člana.

Budući da je this objekt, koristite ga kao: $this->member

Budući da self nije objekt, u osnovi je tip koji se automatski odnosi na trenutni razred, vi ga koristite kao: self::member

109
30 сент. Odgovor dobiva MrZebra 30. rujna 2008-09-30 10:26 '08 u 10:26 am 2008-09-30 10:26

$this-> koristi za označavanje specifične instance varijabli klase (varijable članova) ili metoda.

 Example: $derek = new Person(); 

$ derek je sada specifičan primjer osobe. Svaka osoba ima first_name i last_name, ali $ derek ima određeno ime_ime i last_name (Derek Martin). Unutar $ derek primjera, možemo ih uputiti kao $ this-> first_name i $ this-> last_name

ClassName :: koristi se za označavanje ove vrste klase i njenih statičkih varijabli, statičkih metoda. Ako vam to pomaže, možete mentalno zamijeniti riječ "statički" s "zajedničkim". Budući da se dijele, ne mogu se odnositi na $ this, što se odnosi na određenu instancu (nije dijeljena). Statičke varijable (tj. Statički $ db_connection) mogu se dijeliti između svih instanci tipa objekta. Na primjer, svi objekti baze podataka koriste jednu vezu (statična veza $).

Statičke varijable Primjer: Zamislite da imamo klasu baze podataka s jednom članskom varijablom: static $ num_connections; Sada stavite ovo u konstruktora:

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

Baš kao što objekti imaju konstruktore, oni također imaju destruktore koji se izvršavaju kada objekt umre ili ne radi:

 function __destruct() { $num_connections--; } 

Svaki put kada stvorimo novu instancu, povećat ćemo broj veza za jedan. Svaki put kada uništimo ili prestanemo koristiti instancu, smanjujemo broj veza za jedan. Stoga možemo pratiti broj primjeraka objekta baze podataka:

 echo DB::num_connections; 

Budući da je $ num_connections statična (uobičajena), prikazat će ukupan broj aktivnih objekata baze podataka. Možda ste vidjeli ovu tehniku ​​koja se koristi za dijeljenje veza baze podataka između svih instanci klase baze podataka. To je učinjeno jer stvaranje veze s bazom podataka zahtijeva mnogo vremena, tako da je najbolje stvoriti samo jednu i dijeliti je (to se zove Singleton predložak).

Statičke metode (tj. Javni statični pogled :: broj_formata_fona ($ znamenke)) mogu se koristiti bez prve instance jednog od tih objekata (tj. Ne interno se odnose na $ this).

Primjer statičke metode:

 public static function prettyName($first_name, $last_name) { echo ucfirst($first_name).' '.ucfirst($last_name); } echo Person::prettyName($derek->first_name, $derek->last_name); 

Kao što možete vidjeti, javna statička funkcija prettyName ne zna ništa o objektu. Jednostavno radi s parametrima koje prolazite kao normalna funkcija koja nije dio objekta. Zašto se gnjaviti ako to ne možemo učiniti kao dio predmeta?

  1. Prvo, vezanje funkcija na objekte pomaže vam organizirati stvari, tako da znate gdje ih pronaći.
  2. Drugo, to sprečava sukobe imena. U velikom projektu možda imate dva programera koji stvaraju funkcije getName (). Ako stvorite ClassName1 :: getName (), a drugi stvori ClassName2 :: getName (), to uopće nije problem. Nema sukoba. Yay statičke metode!

SELF :: Ako kodirate izvan objekta koji ima statičku metodu kojoj želite pristupiti, morate je pozvati pomoću naziva objekta View :: format_phone_number ($ phone_number); Ako kodirate unutar objekta koji ima statičku metodu na koju se želite pozvati, možete koristiti naziv objekta View :: format_phone_number ($ pn), ili možete koristiti prečicu self :: format_phone_number ($ pn)

Isto vrijedi i za statičke varijable: Primjer: View :: templates_path nasuprot self :: templates_path

Внутри класса DB, если бы мы ссылались на статический метод какого-либо другого объекта, мы использовали бы имя объекта: Example: Session :: getUsersOnline();

Но если класс DB хотел ссылаться на свою собственную статическую переменную, он просто сказал бы себя: Пример: self :: connection;