Kapan harus menggunakan lebih dari $ ini?

1997

Di PHP 5, apa perbedaan antara menggunakan self dan $this?

Kapan masing-masing sesuai?

Casey Watson
sumber
kemungkinan duplikat dari Diri baru vs statis baru
Orangepill
Saya akan bertanya apa perbedaan antara: cont A; $ this-> A and self :: A
timmz

Jawaban:

1728

Jawaban singkat

Gunakan $thisuntuk merujuk ke objek saat ini. Gunakan selfuntuk merujuk ke kelas saat ini. Dengan kata lain, gunakan $this->memberuntuk anggota non-statis, gunakan self::$memberuntuk anggota statis.

Jawaban Lengkap

Berikut adalah contoh penggunaan yang benar dari $thisdan selfuntuk variabel anggota yang tidak statis dan statis:

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

Berikut ini adalah contoh penggunaan salah$this dan selfuntuk variabel anggota tidak-statis dan statis:

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

Berikut adalah contoh polimorfisme dengan $thisuntuk fungsi anggota:

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

Berikut adalah contoh menekan perilaku polimorfik dengan menggunakan selfuntuk fungsi anggota:

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

Idenya adalah yang $this->foo()memanggil foo()fungsi anggota dari apa pun jenis yang tepat dari objek saat ini. Jika objeknya adalah type X, ia memanggil X::foo(). Jika objeknya adalah type Y, ia memanggil Y::foo(). Tetapi dengan self :: foo (), X::foo()selalu dipanggil.

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

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

John Millikin
sumber
330
Jawaban ini terlalu sederhana. Seperti yang ditunjukkan dalam jawaban lain, selfdigunakan dengan operator resolusi lingkup ::untuk merujuk ke kelas saat ini; ini dapat dilakukan dalam konteks statis dan non-statis. Selain itu, sangat sah untuk digunakan $thisuntuk memanggil metode statis (tetapi tidak untuk bidang referensi).
Artefacto
50
Juga pertimbangkan untuk menggunakan static :: bukannya :: self jika Anda menggunakan 5.3+. Itu bisa menyebabkan Anda sakit kepala yang tidak terhitung, lihat jawaban saya di bawah ini untuk alasannya.
Sqoo
25
-1. Jawaban ini menyesatkan, baca jawaban lain untuk info lebih lanjut.
Pacerier
6
Ini mungkin terlalu disederhanakan, tetapi itu menjawab pertanyaan tingkat dasar saya tanpa membuat kepala saya meledak. Saya memang mendapatkan lebih banyak informasi yang saya temukan membantu lebih jauh ke bawah, tetapi untuk sekarang saya hanya mencoba mencari tahu mengapa saya menekan atribut kelas saya dengan $ this-> attrib dan konstanta kelas dengan self :: konstan. Ini membantu saya memahami hal itu dengan lebih baik
MydKnight
Bagaimana dengan $this::?
James
742

Kata kunci sendiri TIDAK merujuk hanya ke 'kelas saat ini', setidaknya tidak dengan cara yang membatasi Anda untuk anggota statis. Dalam konteks anggota non-statis, selfjuga menyediakan cara untuk melewati vtable ( lihat wiki pada vtable ) untuk objek saat ini. Sama seperti yang dapat Anda gunakan parent::methodName()untuk memanggil versi orang tua dari suatu fungsi, sehingga Anda dapat menelepon self::methodName()untuk memanggil implementasi metode saat ini di kelas.

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

Ini akan menampilkan:

Halo, saya Ludwig si pecandu
Selamat tinggal dari Ludwig, orang itu

sayHello()menggunakan $thispointer, sehingga vtable dipanggil untuk memanggil Geek::getTitle(). sayGoodbye()menggunakan self::getTitle(), jadi vtable tidak digunakan, dan Person::getTitle()dipanggil. Dalam kedua kasus, kita berhadapan dengan metode objek yang dipakai, dan memiliki akses ke $thispointer dalam fungsi yang disebut.

tidak elang
sumber
3
Jawaban ini akan lebih baik jika Anda mulai dengan aturan umum daripada pengecualian. Ini masalah gaya, bukan keahlian teknis. Ini adalah contoh terbaik yang pernah saya lihat tentang perbedaan antara self :: dan $ this->, tetapi memalukan untuk menyembunyikannya dengan menyangkal gagasan terlebih dahulu.
adjwilli
3
@adjwilli: Mengapa itu gaya buruk? Tidakkah hal itu meningkatkan kesadaran jika harapan (tesis) OP pertama kali ditolak (antitesis) dan kemudian penjelasannya diberikan sebagai sintesis?
hakre
1
Saya menemukan "kelas saat ini" benar-benar bermasalah. Karena kata kombinasi dapat dipahami sebagai "kelas di mana selfterletak" / "definisi kelas itu adalah bagian literal dari" serta "kelas objek" (yang sebenarnya akan menjadi static).
Jakumi
Bagaimana dengan $this::?
James
1
@ James - tidak ada alasan untuk menggunakan $this::; semua kemungkinan kasus sudah dicakup oleh sintaksis yang lebih umum digunakan. Tergantung pada apa yang Anda maksud, penggunaan $this->, self::atau static::.
ToolmakerSteve
461

JANGAN GUNAKAN self::, gunakanstatic::

Ada aspek lain dari diri :: yang layak disebut. Mengganggu self::mengacu pada ruang lingkup pada titik definisi bukan pada titik eksekusi . Pertimbangkan kelas sederhana ini dengan dua metode:

class Person
{

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

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

}

Jika kita memanggil Person::status()kita akan melihat "Orang itu hidup". Sekarang pertimbangkan apa yang terjadi ketika kita membuat kelas yang mewarisi dari ini:

class Deceased extends Person
{

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

}

Memanggil Deceased::status()kita akan berharap untuk melihat "Orang sudah meninggal" namun apa yang kita lihat adalah "Orang itu hidup" karena ruang lingkup berisi definisi metode asli ketika panggilan ke self::getStatus()didefinisikan.

PHP 5.3 punya solusinya. yang static::menerapkan Operator resolusi "terlambat statis mengikat" yang merupakan cara mewah untuk mengatakan bahwa itu terikat pada lingkup kelas yang disebut. Ubah baris status()menjadi static::getStatus()dan hasilnya adalah apa yang Anda harapkan. Dalam versi PHP yang lebih lama, Anda harus menemukan kludge untuk melakukan ini.

Lihat Dokumentasi PHP

Jadi untuk menjawab pertanyaan tidak seperti yang diminta ...

$this->merujuk ke objek saat ini (turunan dari suatu kelas), sedangkan static::merujuk ke suatu kelas

Sqoo
sumber
6
Bagaimana dengan konstanta kelas?
Kevin Bond
53
"Memanggil Almarhum :: status () kami berharap akan melihat" Orang telah meninggal "". Tidak. Ini adalah panggilan fungsi statis sehingga tidak ada polimorfisme yang terlibat.
cquezel
2
Dari semua kekurangan PHP, saya tidak berpikir ini gila sama sekali. Bagaimana lagi mereka mengizinkan coders untuk menunjuk metode pada kelas saat ini (sebagai lawan melihat mereka di vtable)? Jika mereka menamainya secara berbeda (mungkin dengan menggarisbawahi garis depan) maka orang yang menginginkan fitur ini akan mengkritiknya karena jelek. Selain itu, apa pun nama waras yang mungkin mereka gunakan tampaknya akan selalu ada orang yang mudah bingung yang akan mengkritiknya karena perilaku "gila", mungkin tidak menyadari bagaimana metode pengiriman bahkan bekerja.
mentega
2
Contohnya kelihatannya membingungkan bagi saya: Saya melihat getStatusmetode sebagai metode yang saya sebut contoh kelas, bukan kelas.
Jānis Elmeris
1
@ Sqoo - mengatakan "JANGAN GUNAKAN diri ::, gunakan static ::" adalah poin aneh untuk dibuat - itu sengaja bukan operasi yang sama. Saya pikir poin yang Anda benar-benar buat adalah "lebih jelas jika Anda menggunakan nama kelas aktual 'MyClass ::', daripada 'self ::' . Artinya, jika Anda ingin perilaku self::, Anda bisa mendapatkan itu, kurang membingungkan, dengan menggunakan nama kelas tertentu, mis MyClass::.
ToolmakerSteve
248

Untuk benar-benar memahami apa yang kita bicarakan ketika kita berbicara tentang selflawan $this, kita harus benar-benar menggali apa yang terjadi pada tingkat konseptual dan praktis. Saya benar-benar tidak merasakan jawaban melakukan hal ini dengan tepat, jadi inilah usaha saya.

Mari kita mulai dengan berbicara tentang apa kelas dan objek itu.

Kelas Dan Objek, Secara Konseptual

Jadi, apa adalah sebuah kelas ? Banyak orang mendefinisikannya sebagai cetak biru atau templat untuk suatu objek. Bahkan, Anda dapat membaca lebih lanjut Tentang Kelas Di PHP Di Sini . Dan sampai batas tertentu itulah sebenarnya. Mari kita lihat sebuah kelas:

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

Seperti yang Anda tahu, ada properti di kelas yang dipanggil $namedan metode (fungsi) dipanggil sayHello().

Ini sangat penting untuk dicatat bahwa kelas adalah struktur statis. Yang berarti bahwa kelas Person, setelah didefinisikan, selalu sama di mana pun Anda melihatnya.

Objek di sisi lain adalah apa yang disebut turunan Kelas. Artinya adalah bahwa kita mengambil "cetak biru" kelas, dan menggunakannya untuk membuat salinan yang dinamis. Salinan ini sekarang secara khusus terkait dengan variabel tempat penyimpanannya. Oleh karena itu, setiap perubahan pada instance adalah lokal untuk instance tersebut.

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

Kami membuat instance baru kelas menggunakan newoperator.

Oleh karena itu, kita katakan bahwa Kelas adalah struktur global, dan Obyek adalah struktur lokal. Jangan khawatir tentang ->sintaks lucu itu , kita akan membahasnya sedikit lagi.

Satu hal lain yang harus kita bicarakan, adalah bahwa kita dapat memeriksa apakah instance adalah instanceofkelas tertentu: $bob instanceof Personyang mengembalikan boolean jika $bobinstance dibuat menggunakan Personkelas, atau anak dari Person.

Mendefinisikan Negara

Jadi mari kita gali sedikit ke dalam apa yang sebenarnya mengandung kelas Ada 5 jenis "hal" yang dikandung kelas:

  1. Properti - Pikirkan ini sebagai variabel yang akan berisi setiap instance.

    class Foo {
        public $bar = 1;
    }
  2. Properti Statis - Pikirkan ini sebagai variabel yang dibagikan di tingkat kelas. Berarti mereka tidak pernah disalin oleh setiap contoh.

    class Foo {
        public static $bar = 1;
    }
  3. Metode - Ini adalah fungsi yang masing-masing instance akan berisi (dan beroperasi pada instance).

    class Foo {
        public function bar() {}
    }
  4. Metode Statis - Ini adalah fungsi yang dibagikan di seluruh kelas. Mereka tidak beroperasi pada instance, melainkan pada properti statis saja.

    class Foo {
        public static function bar() {}
    }
  5. Konstanta - Konstanta yang diselesaikan kelas. Tidak masuk lebih dalam di sini, tetapi menambahkan untuk kelengkapan:

    class Foo {
        const BAR = 1;
    }

Jadi pada dasarnya, kami menyimpan informasi pada kelas dan objek kontainer menggunakan "petunjuk" tentang statis yang mengidentifikasi apakah informasi tersebut dibagikan (dan karenanya statis) atau tidak (dan karenanya dinamis).

Negara dan Metode

Di dalam suatu metode, instance objek diwakili oleh $thisvariabel. Keadaan saat objek itu ada di sana, dan bermutasi (mengubah) properti apa pun akan menghasilkan perubahan ke instance itu (tetapi tidak yang lain).

Jika suatu metode disebut secara statis, $thisvariabel tidak didefinisikan . Ini karena tidak ada instance yang terkait dengan panggilan statis.

Yang menarik di sini adalah bagaimana panggilan statis dibuat. Jadi mari kita bicara tentang bagaimana kita mengakses negara:

Mengakses negara

Jadi sekarang kita telah menyimpan status itu, kita perlu mengaksesnya. Ini bisa menjadi sedikit rumit (atau jauh lebih sedikit), jadi mari kita bagi menjadi dua sudut pandang: dari luar instance / kelas (katakanlah dari pemanggilan fungsi normal, atau dari lingkup global), dan di dalam instance / class (dari dalam metode pada objek).

Dari Luar Instance / Kelas

Dari luar instance / kelas, aturan kami cukup sederhana dan dapat diprediksi. Kami memiliki dua operator, dan masing-masing memberi tahu kami segera jika kami berurusan dengan instance atau static kelas:

  • ->- object-operator - Ini selalu digunakan ketika kita mengakses instance.

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

    Penting untuk dicatat bahwa panggilan Person->footidak masuk akal (karena Personkelas, bukan instance). Oleh karena itu, itu adalah kesalahan parse.

  • ::- scope-resolution-operator - Ini selalu digunakan untuk mengakses properti atau metode statis Class.

    echo Foo::bar()

    Selain itu, kita dapat memanggil metode statis pada objek dengan cara yang sama:

    echo $foo::bar()

    Ini sangat penting untuk dicatat bahwa ketika kita melakukan ini dari luar , misalnya objek tersembunyi dari bar()metode. Artinya sama persis dengan menjalankan:

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

Karena itu, $thistidak didefinisikan dalam panggilan statis.

Dari Inside Of An Instance / Class

Banyak hal berubah di sini. Operator yang sama digunakan, tetapi artinya menjadi kabur secara signifikan.

Operator objek -> masih digunakan untuk melakukan panggilan ke keadaan instance objek.

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

Memanggil bar()metode pada $foo(turunan dari Foo) menggunakan objek-operator: $foo->bar()akan menghasilkan versi turunan dari $a.

Jadi itulah yang kami harapkan.

Arti ::operator meskipun berubah. Itu tergantung pada konteks panggilan ke fungsi saat ini:

  • Dalam konteks statis

    Dalam konteks statis, semua panggilan yang dibuat ::juga akan statis. Mari kita lihat sebuah contoh:

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

    Memanggil Foo::bar()akan memanggil baz()metode statis, dan karenanya $thisakan tidak diisi. Perlu dicatat bahwa dalam versi PHP terbaru (5.3+) ini akan memicu E_STRICTkesalahan, karena kami memanggil metode non-statis secara statis.

  • Dalam konteks instance

    Di dalam konteks instance di sisi lain, panggilan yang dibuat menggunakan ::tergantung pada penerima panggilan (metode yang kami panggil). Jika metode ini didefinisikan static, maka akan menggunakan panggilan statis. Jika tidak, itu akan meneruskan informasi instan.

    Jadi, melihat kode di atas, panggilan $foo->bar()akan kembali true, karena panggilan "statis" terjadi di dalam konteks instance.

Masuk akal? Tidak mengira begitu. Ini membingungkan.

Kata kunci pintas

Karena mengikat semuanya bersama-sama menggunakan nama kelas agak kotor, PHP menyediakan 3 kata kunci "jalan pintas" dasar untuk mempermudah penyelesaian ruang lingkup.

  • self- Ini merujuk pada nama kelas saat ini. Jadi self::baz()sama dengan Foo::baz()di dalam Fookelas (metode apa pun di atasnya).

  • parent - Ini merujuk pada induk dari kelas saat ini.

  • static- Ini mengacu pada kelas yang dipanggil. Berkat warisan, kelas anak dapat menimpa metode dan properti statis. Jadi memanggil mereka menggunakan staticbukan nama kelas memungkinkan kita untuk menyelesaikan dari mana panggilan itu berasal, daripada tingkat saat ini.

Contohnya

Cara termudah untuk memahami ini adalah mulai melihat beberapa contoh. Mari pilih kelas:

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

Sekarang, kami juga melihat warisan di sini. Abaikan sejenak bahwa ini adalah model objek yang buruk, tetapi mari kita lihat apa yang terjadi ketika kita bermain dengan ini:

$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

Jadi penghitung ID dibagikan di seluruh instance dan anak-anak (karena kami menggunakan selfuntuk mengaksesnya. Jika kami menggunakannya static, kami bisa menimpanya dalam kelas anak).

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

Perhatikan bahwa kami menjalankan metode Person::getName() instance setiap waktu. Tapi kami menggunakan parent::getName()untuk melakukannya di salah satu kasus (kasus anak). Inilah yang membuat pendekatan ini kuat.

Perhatian # 1

Perhatikan bahwa konteks panggilan adalah yang menentukan apakah instance digunakan. Karena itu:

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

Tidak selalu benar.

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

Sekarang benar - benar aneh di sini. Kami memanggil kelas yang berbeda, tetapi $thisyang diteruskan ke Foo::isFoo()metode adalah turunan dari $bar.

Ini dapat menyebabkan semua jenis bug dan WTF-ery konseptual. Jadi saya akan sangat menyarankan menghindari ::operator dari dalam metode instan pada apa pun kecuali yang tiga virtual "short-cut" kata kunci ( static, self, dan parent).

Perhatian # 2

Perhatikan bahwa metode dan properti statis dibagikan oleh semua orang. Itu membuat mereka pada dasarnya variabel global. Dengan semua masalah yang sama dengan global. Jadi saya akan benar-benar ragu untuk menyimpan informasi dalam metode / properti statis kecuali Anda merasa nyaman dengan itu menjadi benar-benar global.

Perhatian # 3

Secara umum, Anda ingin menggunakan apa yang dikenal sebagai Late-Static-Binding dengan menggunakan staticalih-alih self. Tetapi perhatikan bahwa mereka bukan hal yang sama, jadi mengatakan "selalu gunakan staticbukannya selfbenar-benar picik. Sebaliknya, berhenti dan pikirkan tentang panggilan yang ingin Anda buat dan pikirkan jika Anda ingin kelas anak-anak dapat menimpa statis yang diselesaikan panggilan.

TL / DR

Sayang sekali, kembali dan baca. Mungkin terlalu lama, tapi itu lama karena ini adalah topik yang kompleks

TL / DR # 2

Baiklah. Singkatnya, selfdigunakan untuk mereferensikan nama kelas saat ini di dalam kelas, di mana $thismerujuk pada instance objek saat ini . Perhatikan bahwa itu selfadalah jalan pintas salin / tempel. Anda dapat dengan aman menggantinya dengan nama kelas Anda, dan itu akan berfungsi dengan baik. Tetapi $thisadalah variabel dinamis yang tidak dapat ditentukan sebelumnya (dan mungkin bahkan bukan kelas Anda).

TL / DR # 3

Jika objek-operator digunakan ( ->), maka Anda selalu tahu Anda berurusan dengan sebuah instance. Jika lingkup-resolusi-operator digunakan ( ::), Anda memerlukan informasi lebih lanjut tentang konteksnya (apakah kita sudah berada dalam konteks objek? Apakah kita berada di luar objek? Dll).

ircmaxell
sumber
1
Word of Caution # 1: $ this tidak akan didefinisikan saat memanggil metode statis: 3v4l.org/9kr0e
Mark Achée
Yah ... $thistidak akan ditentukan jika Anda mengikuti "Standar Ketat" dan jangan panggil metode statis yang tidak didefinisikan sebagai statis. Saya melihat hasil yang Anda jelaskan di sini: 3v4l.org/WeHVM Setuju, sangat aneh.
Mark Achée
2
Setelah membaca deskripsi panjangnya sepenuhnya, saya merasa malas untuk menggulir ke atas lagi untuk meningkatkannya. Hanya bercanda, saya benar-benar membuatnya jengkel: D. Terima kasih ini sangat bermanfaat.
Mr_Green
3
alangkah baiknya untuk menambahkan penjelasan yang jelas tentang perbedaan antara self :: $ property dan self :: property; Saya pikir itu cukup membingungkan juga
Tommaso Barbugli
1
WoC # 1 berperilaku berbeda sejak PHP 7. Seperti Foo::isFoo()disebut statis, $thistidak akan didefinisikan. Itu perilaku yang lebih intuitif menurut saya. - Hasil lain yang berbeda diberikan jika Bardiperpanjang dari Foo. Maka panggilan Foo::isFoo()akan benar-benar berada dalam konteks instance (tidak spesifik untuk PHP7).
Kontrollfreak
117

self(bukan $ self) mengacu pada jenis kelas, di mana seperti $thismerujuk pada instance kelas saat ini. selfdigunakan untuk fungsi anggota statis untuk memungkinkan Anda mengakses variabel anggota statis. $thisdigunakan dalam fungsi anggota yang tidak statis, dan merupakan referensi ke instance dari kelas di mana fungsi anggota dipanggil.

Karena thisadalah sebuah objek, Anda menggunakannya seperti:$this->member

Karena selfbukan objek, itu pada dasarnya adalah tipe yang secara otomatis merujuk ke kelas saat ini, Anda menggunakannya seperti:self::member

MrZebra
sumber
97

$this-> digunakan untuk merujuk pada instance spesifik dari variabel kelas (variabel anggota) atau metode.

Example: 
$derek = new Person();

$ derek sekarang adalah contoh spesifik dari Person. Setiap Orang memiliki nama depan dan nama belakang, tetapi $ derek memiliki nama depan dan nama belakang tertentu (Derek Martin). Di dalam instance $ derek, kita dapat merujuknya sebagai $ this-> first_name dan $ this-> last_name

ClassName :: digunakan untuk merujuk pada tipe kelas itu, dan variabel statisnya, metode statis. Jika ini membantu, Anda dapat secara mental mengganti kata "statis" dengan "dibagikan". Karena dibagikan, mereka tidak dapat merujuk ke $ this, yang merujuk pada contoh spesifik (tidak dibagikan). Variabel Statis (mis. $ Db_connection statis) dapat dibagi di antara semua instance dari jenis objek. Sebagai contoh, semua objek database berbagi satu koneksi (koneksi $ statis).

Variabel Statis Contoh: Berpura-pura kita memiliki kelas basis data dengan variabel anggota tunggal: static $ num_connections; Sekarang, letakkan ini di konstruktor:

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

Sama seperti objek memiliki konstruktor, mereka juga memiliki destruktor, yang dieksekusi ketika objek mati atau tidak disetel:

function __destruct()
{
    $num_connections--;
}

Setiap kali kita membuat instance baru, penghitung koneksi kita akan bertambah satu. Setiap kali kita menghancurkan atau berhenti menggunakan instance, itu akan mengurangi penghitung koneksi satu per satu. Dengan cara ini, kita dapat memonitor jumlah instance dari objek database yang telah kita gunakan dengan:

echo DB::num_connections;

Karena $ num_connections bersifat statis (dibagi-pakai), ia akan mencerminkan jumlah total objek database aktif. Anda mungkin telah melihat teknik ini digunakan untuk berbagi koneksi database di antara semua instance dari kelas database. Ini dilakukan karena membuat koneksi database membutuhkan waktu lama, jadi yang terbaik untuk membuatnya hanya satu, dan membaginya (ini disebut Pola Singleton).

Metode Statis (yaitu public static View :: format_phone_number ($ digit)) dapat digunakan TANPA pertama-tama instantiating salah satu objek tersebut (yaitu Mereka tidak merujuk secara internal ke $ this).

Contoh Metode Statis:

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

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

Seperti yang Anda lihat, fungsi statis publik prettyName tidak tahu apa-apa tentang objek. Ini hanya bekerja dengan parameter yang Anda lewati, seperti fungsi normal yang bukan bagian dari objek. Lalu, mengapa repot-repot, kalau saja kita tidak memilikinya sebagai bagian dari objek?

  1. Pertama, melampirkan fungsi ke objek membantu Anda mengatur berbagai hal, sehingga Anda tahu di mana menemukannya.
  2. Kedua, ini mencegah konflik penamaan. Dalam proyek besar, Anda cenderung memiliki dua pengembang membuat fungsi getName (). Jika satu membuat ClassName1 :: getName (), dan yang lain membuat ClassName2 :: getName (), tidak ada masalah sama sekali. Tidak ada konflik. Yay metode statis!

DIRI :: Jika Anda melakukan pengkodean di luar objek yang memiliki metode statis yang ingin Anda rujuk, Anda harus memanggilnya menggunakan nama objek View :: format_phone_number ($ phone_number); Jika Anda mengkode di dalam objek yang memiliki metode statis yang ingin Anda lihat, Anda bisa melakukannya menggunakan objek nama View :: format_phone_number ($ pn), ATAU Anda dapat menggunakan self :: format_phone_number ($ pn) shortcut

Hal yang sama berlaku untuk variabel statis: Contoh: Lihat :: templates_path versus self :: templates_path

Di dalam kelas DB, jika kita merujuk pada metode statis dari beberapa objek lain, kita akan menggunakan nama objek: Contoh: Session :: getUsersOnline ();

Tetapi jika kelas DB ingin merujuk ke variabel statisnya sendiri, ia hanya akan mengatakan sendiri: Contoh: self :: connection;

Semoga itu membantu menjernihkan semuanya :)

lo_fye
sumber
Jawaban yang bagus Saya hanya ingin menunjukkan, ketika merujuk ke atribut statis, Anda harus menggunakan $tanda. Misalnyaself::$templates_path
henrywright
30

Dari posting blog ini :

  • self merujuk ke kelas saat ini
  • self dapat digunakan untuk memanggil fungsi statis dan referensi variabel anggota statis
  • self dapat digunakan di dalam fungsi statis
  • self juga dapat mematikan perilaku polimorfik dengan memintas vtable
  • $this mengacu pada objek saat ini
  • $this dapat digunakan untuk memanggil fungsi statis
  • $thistidak boleh digunakan untuk memanggil variabel anggota statis. Gunakan selfsebagai gantinya.
  • $this tidak dapat digunakan di dalam fungsi statis
okconfused
sumber
26

Di PHP, Anda menggunakan kata kunci mandiri untuk mengakses properti dan metode statis.

Masalahnya adalah Anda dapat mengganti $this->method()dengan self::method()mana saja, terlepas dari apakah method()dinyatakan statis atau tidak. Jadi yang mana yang harus Anda gunakan?

Pertimbangkan kode ini:

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

Dalam contoh ini, self::who()akan selalu menampilkan 'induk', sementara $this->who()akan bergantung pada kelas apa yang dimiliki objek.

Sekarang kita dapat melihat bahwa diri merujuk ke kelas yang disebutnya, sementara $thismengacu pada kelas objek saat ini .

Jadi, Anda harus menggunakan diri sendiri saat $this tidak tersedia, atau ketika Anda tidak ingin mengizinkan kelas turunan untuk menimpa metode saat ini.

ramin rostami
sumber
22

Di dalam definisi kelas, $thismengacu pada objek saat ini, sementaraself mengacu pada kelas saat ini.

Kita perlu merujuk ke elemen kelas menggunakan self, dan merujuk ke elemen objek menggunakan $this.

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

Berikut adalah contoh penggunaan $ this yang benar dan mandiri untuk variabel anggota yang tidak statis dan statis:

<?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();
?> 
Mohit Bumb
sumber
21

Menurut http://www.php.net/manual/en/language.oop5.static.php tidak ada $self. Hanya ada $this, untuk merujuk ke instance kelas saat ini (objek), dan diri, yang dapat digunakan untuk merujuk ke anggota statis kelas. Perbedaan antara instance objek dan kelas mulai berlaku di sini.

kejam
sumber
9
Saran: Baca jawaban ini saat tersandung asam.
20
16

Saya percaya pertanyaannya bukan apakah Anda dapat memanggil anggota statis kelas dengan menelepon ClassName::staticMember. Pertanyaannya adalah apa perbedaan antara menggunakan self::classmemberdan $this->classmember.

Misalnya, kedua contoh berikut berfungsi tanpa kesalahan, baik Anda menggunakan self::atau$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;
    }
}
Rotimi
sumber
Sangat lucu bahwa Anda memulai jawaban Anda dengan "Saya percaya pertanyaan itu bukan apakah Anda dapat memanggil anggota statis kelas dengan memanggil ClassName :: staticMember. Pertanyaannya adalah apa perbedaan antara menggunakan self :: classmember dan $ this-> classmember" dan kemudian Anda melanjutkan untuk tidak menunjukkan perbedaan sama sekali. Bahkan, Anda menunjukkan contoh tempat dua opsi bekerja secara identik. -1
Buttle Butkus
Meskipun demikian bermanfaat. Cakupannya tentang resolusi dan bagian ini tidak jelas dalam manual php. Saya masih merasakan
manfaatnya
2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun
16

self merujuk kelas saat ini (di mana ia disebut),

$thismerujuk objek saat ini. Anda dapat menggunakan statis alih-alih mandiri. Lihat contohnya:

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

Keluaran: orangtua anak

Kabir Hossain
sumber
16
  • Pointer objek $thisuntuk merujuk ke objek saat ini.
  • Nilai kelas staticmengacu pada objek saat ini.
  • Nilai kelas selfmerujuk ke kelas tepat yang didefinisikan dalam.
  • Nilai kelas parentmengacu pada induk dari kelas yang tepat itu didefinisikan dalam.

Lihat contoh berikut yang menunjukkan kelebihan beban.

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

Sebagian besar waktu Anda ingin merujuk ke kelas saat ini yang mengapa Anda menggunakan staticatau $this. Namun, ada kalanya Anda membutuhkannya self karena Anda menginginkan kelas asli terlepas dari apa yang meluasnya. (Sangat, sangat jarang)

Xeoncross
sumber
14

Karena tidak seorang pun di sini berbicara tentang pertunjukan, berikut ini adalah tolok ukur kecil yang saya lakukan (5.6):

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

Itu adalah hasil untuk 2 000 000 berjalan, dan di sini adalah kode yang saya gunakan:

<?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();
tleb
sumber
1
Memanggil fungsi no-op 2 000 000 kali berlangsung 1s. Harus mencintai PHP.
rr-
PHP tua yang bagus. :) Tapi panggilan = 0,001 ms. Apakah seburuk itu?
tleb
Saya percaya ini (dan hal-hal serupa) adalah mengapa hal-hal seperti ORM terasa lambat kecuali jika Anda melakukan cache, dan generator situs statis adalah sesuatu.
rr-
2
Secara teori seharusnya mengambil 1 siklus clock prosesor, yang membuat sekitar 1 / 2e9 s = 0.5 nshari-hari ini
Buddy
Baca kembali jawabanku. Hati-hati: itu menciptakan kelas juga. Saya tidak tahu mengapa saya tidak menggunakan usekata kunci tbh, tapi saya tidak punya PHP lagi untuk mengulang tolok ukur, dan saya tidak merasa ingin menginstalnya kembali.
tleb
13

Ketika selfdigunakan dengan ::operator itu merujuk ke kelas saat ini, yang dapat dilakukan baik dalam konteks statis dan non-statis. $thismengacu pada objek itu sendiri. Selain itu, sangat sah untuk digunakan $thisuntuk memanggil metode statis (tetapi tidak merujuk ke bidang).

mrDjouk
sumber
8

Saya mengalami pertanyaan yang sama dan jawaban sederhana adalah:

  • $this membutuhkan turunan dari kelas
  • self:: tidak

Setiap kali Anda menggunakan metode statis atau atribut statis dan ingin memanggil mereka tanpa objek dari kelas Anda perlu menggunakan self:untuk memanggil mereka, karena $thisselalu membutuhkan objek yang akan dibuat.

Mike
sumber
7

$thismerujuk ke objek kelas saat ini, selfmengacu ke kelas saat ini (Bukan objek). Kelas adalah cetak biru objek. Jadi Anda mendefinisikan kelas, tetapi Anda membangun objek.

Jadi dengan kata lain, gunakan self for staticdan this for none-static members or methods.

juga dalam skenario anak / orang tua self / parentsebagian besar digunakan untuk mengidentifikasi anggota dan metode kelas anak dan orang tua.

Rakesh Singh
sumber
7

Selain itu karena $this::belum dibahas.

Hanya untuk tujuan informasi, pada PHP 5.3 ketika berhadapan dengan objek instantiated untuk mendapatkan nilai lingkup saat ini, sebagai lawan dari penggunaan static::, seseorang dapat menggunakan $this::seperti itu.

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

Menggunakan kode di atas bukan praktik yang umum atau disarankan, tetapi hanya untuk menggambarkan penggunaannya, dan bertindak sebagai lebih dari "Tahukah Anda?" mengacu pada pertanyaan poster asli.

Ini juga mewakili penggunaan $object::CONSTANTmisalnya echo $foo::NAME;sebagai lawan$this::NAME;

fyrye
sumber
5

Gunakan selfjika Anda ingin memanggil metode kelas tanpa membuat objek / instance kelas itu, sehingga menghemat RAM (kadang-kadang menggunakan diri untuk tujuan itu). Dengan kata lain, sebenarnya memanggil metode secara statis. Gunakan thisuntuk perspektif objek.

minhajul
sumber
2

Kasus 1: Penggunaan selfdapat digunakan untuk konstanta kelas

 class classA { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}

Jika Anda ingin menyebutnya di luar kelas, gunakan classA::POUNDS_TO_KILOGRAMSuntuk mengakses konstanta

Kasus 2: Untuk properti statis

class classC {
     fungsi publik __construct () { 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}
li bing zhao
sumber
1

Menurut php.net ada tiga kata kunci khusus dalam konteks ini: self, parentdan static. Mereka digunakan untuk mengakses properti atau metode dari dalam definisi kelas.

$this, di sisi lain, digunakan untuk memanggil instance dan metode dari kelas apa saja selama kelas itu dapat diakses.

Fil
sumber
-1

self ::  kata kunci yang digunakan untuk kelas saat ini dan pada dasarnya digunakan untuk mengakses anggota statis, metode, dan konstanta. Tetapi dalam kasus $ this Anda tidak dapat memanggil anggota statis, metode dan fungsi.

Anda dapat menggunakan kata kunci self :: di kelas lain dan mengakses anggota statis, metode, dan konstanta. Ketika akan diperluas dari kelas induk dan sama dalam kasus $ kata kunci ini . Anda dapat mengakses anggota, metode, dan fungsi yang tidak statis di kelas lain ketika akan diperluas dari kelas induk.

Kode yang diberikan di bawah ini adalah contoh dari self :: dan $ this keyword. Cukup salin dan tempel kode dalam file kode Anda dan lihat hasilnya.

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());
Deepak Syal
sumber