Apa perbedaan antara self :: $ bar dan static :: $ bar di PHP?

125

Apa perbedaan antara menggunakan selfdan staticpada contoh di bawah ini?

class Foo
{
    protected static $bar = 1234;

    public static function instance()
    {
        echo self::$bar;
        echo "\n";
        echo static::$bar;
    }

}

Foo::instance();

menghasilkan

1234
1234
cwd
sumber
2
@deceze: Itu pertanyaan yang mirip, tapi ini bukan duplikat. Yang satu ini menanyakan tentang menggunakan kata kunci dengan properti, sedangkan yang menanyakan tentang menggunakannya dengan konstruktor.
BoltClock

Jawaban:

191

Saat Anda menggunakan selfuntuk merujuk ke anggota kelas, Anda merujuk ke kelas di mana Anda menggunakan kata kunci. Dalam kasus ini, Fookelas Anda mendefinisikan properti statis yang dilindungi yang disebut $bar. Saat Anda menggunakan selfdi Fookelas untuk merujuk ke properti, Anda merujuk ke kelas yang sama.

Oleh karena itu jika Anda mencoba untuk menggunakan self::$bartempat lain di Anda Fookelas tetapi Anda memiliki Barkelas dengan nilai yang berbeda untuk properti, itu akan menggunakan Foo::$barbukan Bar::$bar, yang mungkin tidak apa yang Anda berniat:

class Foo
{
    protected static $bar = 1234;
}

class Bar extends Foo
{
    protected static $bar = 4321;
}

Saat Anda memanggil metode lewat static, Anda memanggil fitur yang disebut late static bindings (diperkenalkan di PHP 5.3).

Dalam skenario di atas, penggunaan selfakan menghasilkan Foo::$bar(1234). Dan menggunakan staticakan menghasilkan Bar::$bar(4321) karena with static, interpreter memperhitungkan deklarasi ulang dalam Barkelas selama runtime.

Anda biasanya menggunakan binding statis terbaru untuk metode atau bahkan kelas itu sendiri, daripada properti, karena Anda tidak sering mendeklarasikan ulang properti di subkelas; contoh penggunaan statickata kunci untuk memanggil konstruktor terikat-akhir dapat ditemukan dalam pertanyaan terkait ini: Diri baru vs. statis baru

Namun, itu juga tidak menghalangi penggunaan staticwith properti.

BoltClock
sumber
Anda dapat dengan mudah mendeklarasikan ulang di kelas anak, kelas induk mungkin merupakan nilai default yang digunakan kelas anak kecuali mereka mendeklarasikan ulang. Jika Anda berada di kelas induk, saya rasa aman untuk menggunakan self ::, dan jika di kelas anak, Anda dapat membuat argumen untuk menggunakan salah satunya, tetapi self :: juga akan berfungsi jika Anda tidak mengharapkannya. nyatakan kembali pernah.
Andrew
3
buka phpfiddle.org dan jalankan ini<?php class Foo { public static $bar = 1234; public static function a( ) { echo 'static'.static::$bar; echo 'self'.self::$bar; } } class Bar extends Foo { public static $bar = 4321; } (new Bar())->a(); ?>
Yevgeniy Afanasyev
2
Kata-kata dalam dua paragraf pertama membingungkan, memiliki kata ganti ambigu, "it", dan juga berlebihan, karena paragraf selanjutnya menjelaskan informasi yang sama dengan lebih jelas. Saya sarankan untuk mengganti dua paragraf pertama dengan paragraf berikutnya yang dimulai dengan "Dalam skenario di atas" ke atas. Dengan begitu, intinya, jawaban langsung adalah di atas. Jelas dan mudah diikuti.
ahnbizcad
Cara lain untuk memikirkan ini:, self::$abcketika digunakan di class Foodalam sama dengan mengatakan Foo::$abc. Itu tidak akan terpengaruh oleh deklarasi ulang apa pun $abcdalam subclass. AFAIK, satu-satunya alasan penggunaan selfadalah sebagai singkatan, untuk menghindari penggunaan nama kelas Foo, yang mungkin lebih panjang. [Ini juga berarti Anda dapat mengubah nama kelas tanpa mengubah semua tempat itu - tapi itu bukan alasan IMHO.] (Pilihan nama PHP sangat disayangkan, dan tampaknya mundur; "statis" adalah salah satu yang dapat berubah - yang mana berlawanan dengan arti sehari-hari dari kata bahasa alami "statis".)
ToolmakerSteve
4

Seperti yang disebutkan, salah satu perbedaan utama adalah staticmemungkinkan binding statis terlambat. Salah satu skenario paling berguna yang saya temukan adalah untuk membuat kelas Basis untuk Kelas Singleton:

class A { // Base Class
    protected static $name = '';
    protected static function getName() {
        return static::$name;
    }
}
class B extends A {
    protected static $name = 'MyCustomNameB';
}
class C extends A {
    protected static $name = 'MyCustomNameC';
}

echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC

Menggunakan return static::$namedi kelas Base akan mengembalikan apa yang terpasang secara statis saat diperpanjang. Jika Anda menggunakan return self::$namemaka B::getName()akan mengembalikan string kosong seperti yang dideklarasikan di kelas Base.

ggedde
sumber
0

Dengan selfpanggilan:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return self::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "123"
echo (new Bar)->getVar();

Anda dapat melihat di atas, meskipun kita telah menimpa $vardengan Barkelas kita , itu tetap kembali 123, karena kita secara eksplisit meminta selfvariabel PHP , yang pada gilirannya meminta Foovariabel s sebagai gantinya.

Sekarang jika kita menukar panggilan dengan static, kita akan mendapatkan Barnilai yang diganti:

Dengan staticpanggilan:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return static::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "234"
echo (new Bar)->getVar();
Steve Bauman
sumber