อะไรคือความแตกต่างระหว่าง self :: $ bar และ static :: $ bar ใน PHP?


125

ความแตกต่างระหว่างการใช้selfและstaticในตัวอย่างด้านล่างคืออะไร?

class Foo
{
    protected static $bar = 1234;

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

}

Foo::instance();

ผลิต

1234
1234

2
@deceze: นั่นเป็นคำถามที่คล้ายกัน แต่ไม่ใช่เรื่องที่ซ้ำกัน อันนี้ถามเกี่ยวกับการใช้คีย์เวิร์ดกับคุณสมบัติในขณะที่ถามเกี่ยวกับการใช้คีย์เวิร์ดกับคอนสตรัคเตอร์
BoltClock

คำตอบ:


191

เมื่อคุณใช้selfเพื่ออ้างถึงสมาชิกชั้นเรียนคุณกำลังหมายถึงคลาสที่คุณใช้คีย์เวิร์ด ในกรณีนี้คุณระดับกำหนดคุณสมบัติการป้องกันแบบคงที่เรียกว่าFoo $barเมื่อคุณใช้selfในFooคลาสเพื่ออ้างถึงคุณสมบัติคุณกำลังอ้างถึงคลาสเดียวกัน

ดังนั้นหากคุณพยายามใช้self::$barที่อื่นในFooชั้นเรียนของคุณแต่คุณมีBarคลาสที่มีค่าคุณสมบัติต่างกันจะใช้Foo::$barแทนBar::$barซึ่งอาจไม่ใช่สิ่งที่คุณตั้งใจ:

class Foo
{
    protected static $bar = 1234;
}

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

เมื่อคุณเรียกใช้เมธอดstaticคุณกำลังเรียกใช้คุณลักษณะที่เรียกว่าการโยงแบบคงที่ในช่วงปลาย (แนะนำใน PHP 5.3)

ในสถานการณ์ข้างต้นการใช้selfจะให้ผลลัพธ์เป็นFoo::$bar(1234) และการใช้staticจะให้ผลลัพธ์เป็นBar::$bar(4321) เนื่องจากด้วยstaticตัวแปลจะคำนึงถึงการประกาศซ้ำภายในBarคลาสระหว่างรันไทม์

โดยทั่วไปคุณจะใช้การเชื่อมแบบคงที่ในช่วงปลายสำหรับเมธอดหรือแม้แต่คลาสเองแทนที่จะใช้คุณสมบัติเนื่องจากคุณมักจะไม่ประกาศคุณสมบัติซ้ำในคลาสย่อย ตัวอย่างของการใช้staticคีย์เวิร์ดสำหรับการเรียกใช้คอนสตรัคเตอร์แบบผูกปลายสามารถพบได้ในคำถามที่เกี่ยวข้องนี้: ตัวใหม่กับสแตติกใหม่

อย่างไรก็ตามนั่นไม่ได้กีดกันการใช้staticกับคุณสมบัติเช่นกัน


คุณสามารถประกาศซ้ำในคลาสลูกได้อย่างง่ายดายคลาสแม่อาจเป็นค่าเริ่มต้นที่คลาสลูกใช้เว้นแต่จะประกาศใหม่ หากคุณอยู่ในคลาสผู้ปกครองฉันเดาว่าปลอดภัยที่จะใช้ self :: และหากอยู่ในคลาสย่อยคุณสามารถใช้อาร์กิวเมนต์ใดก็ได้ แต่ self :: จะใช้ได้เช่นกันหากคุณไม่คาดหวัง ประกาศอีกครั้ง
Andrew

3
ไปที่phpfiddle.orgและเรียกใช้<?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
การใช้ถ้อยคำสองย่อหน้าแรกทำให้สับสนมีสรรพนามที่ไม่ชัดเจน "มัน" และยังมีการเรียกซ้ำอีกด้วยเนื่องจากย่อหน้าต่อมาอธิบายข้อมูลเดียวกันได้ชัดเจนยิ่งขึ้น ฉันขอแนะนำให้แทนที่สองย่อหน้าแรกด้วยย่อหน้าต่อมาที่ขึ้นต้นด้วย "ในสถานการณ์ข้างต้น" ไปด้านบน ด้วยวิธีนี้บรรทัดล่างสุดคำตอบแบบตัดต่อไล่จะอยู่ที่ด้านบน มันชัดเจนและง่ายต่อการปฏิบัติ
ahnbizcad

อีกวิธีหนึ่งที่จะคิดเกี่ยวกับเรื่องนี้: self::$abcเมื่อภายในที่ใช้เป็นเช่นเดียวกับการพูดว่าclass Foo Foo::$abcจะไม่ได้รับผลกระทบจากการประกาศซ้ำ$abcในคลาสย่อย AFAIK เหตุผลเดียวที่ใช้selfคือชวเลขเพื่อหลีกเลี่ยงการใช้ชื่อชั้นเรียนFooซึ่งอาจยาวกว่า [นอกจากนี้ยังหมายความว่าคุณสามารถเปลี่ยนชื่อคลาสได้โดยไม่ต้องเปลี่ยนสถานที่เหล่านั้นทั้งหมด - แต่นั่นก็ไม่ใช่เหตุผลที่ IMHO มากนัก] (การเลือกชื่อของ PHP นั้นโชคร้ายและดูเหมือนว่าถอยหลัง "คงที่" คือชื่อที่สามารถเปลี่ยนแปลงได้ซึ่ง ตรงข้ามกับความหมายทางภาษาของคำภาษาธรรมชาติ "คงที่")
ToolmakerSteve

4

ดังที่ได้กล่าวไปแล้วข้อแตกต่างหลักประการหนึ่งคือการstaticอนุญาตให้มีการผูกแบบคงที่ หนึ่งในสถานการณ์ที่มีประโยชน์ที่สุดที่ฉันพบคือการสร้างคลาสพื้นฐานสำหรับคลาส 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

การใช้return static::$nameในคลาสฐานจะส่งคืนสิ่งที่แนบมาแบบคงที่เมื่อขยายออก ถ้าคุณได้ใช้return self::$nameแล้วB::getName()จะกลับมาเป็นสตริงว่างเป็นว่าเป็นสิ่งที่ถูกประกาศในระดับฐาน


1

ด้วยการselfโทร:

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

คุณสามารถดูด้านบนแม้ว่าเราจะลบล้างคลาส$varของเราไปBarแล้ว แต่ก็ยังคงส่งคืน123เนื่องจากเราได้ถาม PHP อย่างชัดเจนสำหรับselfตัวแปรซึ่งจะขอFooตัวแปร s แทน

ตอนนี้ถ้าเราสลับสายด้วยstaticเราจะได้รับBarค่า s overridden แทน:

ด้วยการstaticโทร:

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();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.