เมื่อใดควรใช้ตัวเองกับ $ นี่


1997

ใน PHP 5 อะไรคือความแตกต่างระหว่างการใช้selfและ$this?

แต่ละคนมีความเหมาะสมเมื่อใด


มีความเป็นไปได้ที่ซ้ำกันของตัวเองใหม่กับแบบคงที่ใหม่
Orangepill

ฉันจะถามว่าอะไรคือความแตกต่างระหว่าง: cont A; $ this-> A and self :: A
timmz

คำตอบ:


1727

คำตอบสั้น ๆ

ใช้$thisเพื่ออ้างถึงวัตถุปัจจุบัน ใช้selfเพื่ออ้างถึงคลาสปัจจุบัน กล่าวอีกนัยหนึ่งใช้ $this->memberสำหรับสมาชิกที่ไม่คงที่ใช้self::$memberสำหรับสมาชิกคงที่

คำตอบแบบเต็ม

นี่คือตัวอย่างของการใช้งานที่ถูกต้องของ$thisและselfสำหรับตัวแปรสมาชิกแบบไม่คงที่และแบบคงที่:

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

นี่คือตัวอย่างของการใช้งานที่ไม่ถูกต้องของ$thisและselfสำหรับสมาชิกที่ไม่คงที่และคงที่:

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

นี่คือตัวอย่างของความแตกต่างที่มี$thisฟังก์ชั่นสมาชิก

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

นี่คือตัวอย่างของการยับยั้งพฤติกรรม polymorphicโดยใช้selfสำหรับฟังก์ชันสมาชิก:

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

แนวคิดคือ$this->foo()เรียกfoo()ฟังก์ชันสมาชิกของสิ่งที่เป็นชนิดที่แน่นอนของวัตถุปัจจุบัน ถ้าวัตถุเป็นของมันจึงเรียกtype X X::foo()ถ้าวัตถุเป็นของมันเรียกtype Y Y::foo()แต่ด้วยตัวเอง :: foo () X::foo()มักถูกเรียก

จากhttp://www.phpbuilder.com/board/showthread.php?t=10354489 :

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


330
คำตอบนี้ง่ายเกินไป ตามที่ระบุไว้ในคำตอบอื่น ๆselfจะใช้กับตัวดำเนินการแก้ไขขอบเขต::เพื่ออ้างอิงคลาสปัจจุบัน สิ่งนี้สามารถทำได้ทั้งในบริบทคงที่และไม่คงที่ นอกจากนี้การใช้$thisวิธีการแบบคงที่นั้นถูกต้องตามกฎหมายอย่างสมบูรณ์
Artefacto

50
ลองพิจารณาใช้ static :: แทนที่จะเป็น :: self หากคุณใช้ 5.3+ มันอาจทำให้คุณปวดหัวอย่างอื่นไม่ได้ดูคำตอบของฉันด้านล่างสำหรับสาเหตุ
Sqoo

25
-1 คำตอบนี้ทำให้เข้าใจผิดอ่านคำตอบอื่น ๆ สำหรับข้อมูลเพิ่มเติม
Pacerier

6
มันอาจจะง่ายเกินไป แต่มันก็ตอบคำถามระดับพื้นฐานของฉันโดยไม่ทำให้หัวของฉันระเบิด ฉันได้รับข้อมูลเพิ่มเติมที่ฉันคิดว่ามีประโยชน์มากขึ้น แต่ตอนนี้ฉันแค่พยายามหาสาเหตุว่าทำไมฉันถึงตีคุณลักษณะชั้นเรียนด้วย $ this-> attrib และค่าคงที่ของชั้นเรียนด้วยตนเอง :: ค่าคงที่ สิ่งนี้ช่วยให้ฉันเข้าใจดีขึ้น
MydKnight

เกี่ยวกับ$this::อะไร
James

742

คำหลักนั้นไม่ได้อ้างถึงเพียงแค่ 'คลาสปัจจุบัน' อย่างน้อยก็ไม่ใช่ในแบบที่ จำกัด ให้คุณเป็นสมาชิกแบบสแตติก ภายในบริบทของสมาชิกที่ไม่คงที่selfยังมีวิธีการข้าม vtable ( ดูวิกิบน vtable ) สำหรับวัตถุปัจจุบัน เช่นเดียวกับที่คุณสามารถใช้parent::methodName()เพื่อเรียกใช้ฟังก์ชัน parent เวอร์ชันดังนั้นคุณสามารถเรียกใช้self::methodName()การเรียกคลาสปัจจุบันของเมธอดได้

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

สิ่งนี้จะออก:

สวัสดีค่ะฉันลุดวิกเป็นคนที่รัก
ลาก่อนจากลุดวิกเป็นคน

sayHello()ใช้$thisตัวชี้เพื่อ vtable Geek::getTitle()จะเรียกเพื่อโทร sayGoodbye()ใช้self::getTitle()ดังนั้น vtable ไม่ได้ใช้และPerson::getTitle()ถูกเรียกใช้ ในทั้งสองกรณีเรากำลังจัดการกับวิธีการของวัตถุ instantiated และมีการเข้าถึง$thisตัวชี้ภายในฟังก์ชั่นที่เรียกว่า


3
คำตอบนี้จะดียิ่งขึ้นถ้าคุณเริ่มต้นด้วยกฎทั่วไปมากกว่าข้อยกเว้น มันเป็นเรื่องของสไตล์ไม่ใช่ความเชี่ยวชาญด้านเทคนิค นี่เป็นตัวอย่างที่ดีที่สุดที่ฉันเคยเห็นความแตกต่างระหว่างตัวเอง :: และ $ this-> แต่มันเป็นความอัปยศที่จะซ่อนมันไว้โดยหักล้างความคิดก่อน
adjwilli

3
@adjwilli: ทำไมรูปแบบที่ไม่ดีนั้นคืออะไร? มันไม่ได้ทำให้มีสติถ้าความคาดหวัง (วิทยานิพนธ์) ของ OP ไม่ได้รับการอนุมัติเป็นครั้งแรก (ตรงกันข้าม) และคำอธิบายนั้นได้รับการสังเคราะห์หรือไม่
hakre

1
ฉันพบว่า "คลาสปัจจุบัน" มีปัญหาจริงๆ เนื่องจากการรวมกันของคำนั้นสามารถเข้าใจได้ทั้ง "คลาสที่selfตั้งอยู่" / "คำจำกัดความของคลาสมันเป็นส่วนที่แท้จริงของ" เช่นเดียวกับ "คลาสของวัตถุ" (ซึ่งจริง ๆ แล้วจะเป็นstatic)
จากุมิ

เกี่ยวกับ$this::อะไร
James

1
@ James - ไม่มีเหตุผลที่ดีที่จะใช้$this::; ทุกกรณีที่เป็นไปได้ถูกครอบคลุมโดยไวยากรณ์ที่ใช้กันทั่วไปมากกว่า ทั้งนี้ขึ้นอยู่กับสิ่งที่คุณหมายถึงการใช้งาน$this->, หรือself:: static::
ToolmakerSteve

461

ห้ามใช้self::ใช้งานstatic::

มีแง่มุมอื่นของตัวเอง :: ที่น่ากล่าวถึง annoyingly หมายถึงขอบเขตที่จุดของความหมายที่ไม่ได้อยู่ที่จุดของการดำเนินการself:: ลองพิจารณาคลาสง่ายๆนี้ด้วยสองวิธี:

class Person
{

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

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

}

หากเราโทรหาPerson::status()เราจะเห็น "บุคคลมีชีวิตอยู่" พิจารณาสิ่งที่เกิดขึ้นเมื่อเราสร้างคลาสที่สืบทอดจากสิ่งนี้:

class Deceased extends Person
{

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

}

โทรDeceased::status()เราคาดว่าจะเห็น "บุคคลจะตาย" แต่สิ่งที่เราเห็นคือ "คนที่ยังมีชีวิตอยู่" เป็นขอบเขตมีความหมายวิธีการเดิมเมื่อการเรียกร้องให้self::getStatus()ถูกกำหนด

PHP 5.3 มีทางออก static::ความละเอียดการดำเนินการผู้ประกอบการ "คงที่ปลายผูกพัน" ซึ่งเป็นวิธีที่จินตนาการของบอกว่าก็ผูกพันกับขอบเขตของระดับที่เรียกว่า เปลี่ยนบรรทัดstatus()เป็น static::getStatus()และผลลัพธ์คือสิ่งที่คุณคาดหวัง ใน PHP เวอร์ชั่นเก่าคุณจะต้องหา kludge เพื่อทำสิ่งนี้

ดูเอกสาร PHP

ดังนั้นเพื่อตอบคำถามที่ไม่ได้ถาม ...

$this->อ้างถึงวัตถุปัจจุบัน (อินสแตนซ์ของคลาส) ในขณะที่static::อ้างอิงถึงคลาส


6
สิ่งที่เกี่ยวกับค่าคงที่ระดับ?
เควินบอนด์

53
"สถานะการโทรถึงแก่ชีวิต :: () เราคาดว่าจะเห็น" บุคคลนั้นถึงแก่กรรม "" ไม่นี่คือการเรียกใช้ฟังก์ชันแบบสแตติกดังนั้นจึงไม่เกี่ยวข้องกับความหลากหลาย
cquezel

2
ในบรรดาข้อบกพร่องของ PHP ฉันไม่คิดว่ามันบ้าอะไรเลย พวกเขาจะอนุญาตให้ coders กำหนดวิธีการในคลาสปัจจุบันได้อย่างไร (ตรงข้ามกับการค้นหาใน vtable) หากพวกเขาตั้งชื่อมันแตกต่างกัน (อาจจะมีขีดเส้นใต้ชั้นนำ) จากนั้นคนที่ต้องการคุณสมบัตินี้จะวิจารณ์ว่าน่าเกลียด มิฉะนั้นชื่ออะไรก็ตามที่พวกเขาอาจใช้ดูเหมือนว่าจะมีคนสับสนง่าย ๆ ที่จะวิพากษ์วิจารณ์ว่าเป็นคนที่ "บ้า" พฤติกรรมมักจะหลงลืมว่าวิธีการจัดส่งนั้นใช้งานได้อย่างไร
tne

2
ตัวอย่างดูสับสนสำหรับฉัน: ฉันเห็นgetStatusวิธีเป็นวิธีที่ฉันจะเรียกใช้อินสแตนซ์ของชั้นเรียนไม่ใช่สำหรับชั้นเรียน
Jānis Elmeris

1
@Sqoo - การพูดว่า"อย่าใช้ตัวเอง :: ใช้ static ::"เป็นจุดที่แปลกที่จะทำ - สิ่งเหล่านั้นจงใจไม่ใช่การดำเนินการเดียวกัน ฉันคิดว่าจุดที่คุณกำลังทำจริงๆคือ"มันชัดเจนขึ้นถ้าคุณใช้ชื่อคลาสจริง 'MyClass ::' แทน 'self ::'นั่นคือถ้าคุณต้องการพฤติกรรมของself::คุณจะได้รับน้อย อย่างสับสนโดยใช้ชื่อคลาสเฉพาะเช่นMyClass::.
ToolmakerSteve

248

เพื่อให้เข้าใจสิ่งที่เรากำลังพูดถึงเมื่อเราพูดถึงselfเมื่อเทียบกับที่$thisเราต้องขุดจริงในสิ่งที่เกิดขึ้นในระดับแนวคิดและการปฏิบัติ ฉันไม่รู้สึกว่าคำตอบใด ๆ ทำอย่างเหมาะสมดังนั้นนี่คือความพยายามของฉัน

มาเริ่มกันด้วยการพูดคุยกันว่าคลาสและวัตถุคืออะไร

ชั้นเรียนและวัตถุแนวคิด

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

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

ขณะที่คุณสามารถบอกได้มีสถานที่ให้บริการในระดับที่เรียกว่า$nameและวิธีการ (ฟังก์ชั่น) sayHello()ที่เรียกว่า

มันสำคัญมากที่จะต้องทราบว่าคลาสนี้เป็นโครงสร้างแบบสแตติก ซึ่งหมายความว่าคลาสที่Personกำหนดครั้งเดียวจะเหมือนกันทุกที่ที่คุณดู

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

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

เราสร้างอินสแตนซ์ใหม่ของคลาสโดยใช้newโอเปอเรเตอร์

ดังนั้นเราจึงบอกว่าคลาสเป็นโครงสร้างระดับโลกและวัตถุเป็นโครงสร้างในท้องถิ่น ไม่ต้องกังวลเกี่ยวกับ->ไวยากรณ์ที่ตลกเราจะเข้าไปในนั้นเล็กน้อย

สิ่งอื่น ๆ หนึ่งที่เราควรจะพูดคุยเกี่ยวกับการเป็นว่าเราสามารถตรวจสอบถ้าตัวอย่างเป็นinstanceofชั้นโดยเฉพาะอย่างยิ่ง$bob instanceof Personซึ่งผลตอบแทนแบบบูลถ้า$bobอินสแตนซ์ที่ถูกสร้างขึ้นโดยใช้Personชั้นเรียนหรือPersonเด็กของ

กำหนดรัฐ

ลองขุดลงไปในสิ่งที่คลาสมีอยู่จริง มี "สิ่ง" 5 ประเภทที่ชั้นเรียนมี:

  1. คุณสมบัติ - คิดว่าสิ่งเหล่านี้เป็นตัวแปรที่แต่ละอินสแตนซ์จะมี

    class Foo {
        public $bar = 1;
    }
  2. คุณสมบัติคงที่ - คิดว่าสิ่งเหล่านี้เป็นตัวแปรที่ใช้ร่วมกันในระดับชั้นเรียน หมายความว่าไม่มีการคัดลอกโดยแต่ละอินสแตนซ์

    class Foo {
        public static $bar = 1;
    }
  3. วิธีการ - เป็นฟังก์ชั่นที่แต่ละอินสแตนซ์จะมี (และทำงานกับอินสแตนซ์)

    class Foo {
        public function bar() {}
    }
  4. วิธีการคงที่ - เหล่านี้เป็นฟังก์ชั่นที่ใช้ร่วมกันทั่วทั้งชั้นเรียน พวกเขาไม่ทำงานบนอินสแตนซ์ แต่แทนในคุณสมบัติคงที่เท่านั้น

    class Foo {
        public static function bar() {}
    }
  5. ค่าคงที่ - ค่าคงที่คลาสที่แก้ไข ไม่ได้ไปที่นี่ลึก แต่เพิ่มเพื่อความสมบูรณ์:

    class Foo {
        const BAR = 1;
    }

โดยพื้นฐานแล้วเรากำลังจัดเก็บข้อมูลในคลาสและวัตถุคอนเทนเนอร์โดยใช้ "คำแนะนำ" เกี่ยวกับสแตติกซึ่งระบุว่าข้อมูลนั้นถูกแชร์ (และด้วยเหตุนี้คงที่) หรือไม่

รัฐและวิธีการ

ภายในเมธอดอินสแตนซ์ของวัตถุจะถูกแทนด้วย$thisตัวแปร สถานะปัจจุบันของวัตถุนั้นอยู่ที่นั่นและการกลายพันธุ์ (การเปลี่ยนแปลง) คุณสมบัติใด ๆ จะส่งผลให้เกิดการเปลี่ยนแปลงกับอินสแตนซ์นั้น (แต่ไม่ใช่อื่น ๆ )

หากวิธีการที่เรียกว่าแบบคงที่$thisตัวแปรไม่ได้กำหนดไว้ นี่เป็นเพราะไม่มีอินสแตนซ์ที่เกี่ยวข้องกับการโทรคงที่

สิ่งที่น่าสนใจที่นี่คือวิธีการโทรออก ดังนั้นเรามาพูดถึงวิธีที่เราเข้าถึงรัฐ:

การเข้าถึงรัฐ

ดังนั้นตอนนี้ที่เราได้จัดเก็บสถานะนั้นเราต้องเข้าถึงมัน นี้จะได้รับบิตหากิน (หรือวิธีอื่น ๆ อีกมากมายกว่าบิต) จึงขอแยกนี้เป็นสองมุมมอง: จากด้านนอกของอินสแตนซ์ / คลาส (พูดจากสายการทำงานตามปกติหรือจากขอบเขตทั่วโลก) และภายในของอินสแตนซ์ / class (จากภายในเมธอดบนวัตถุ)

จากด้านนอกของอินสแตนซ์ / คลาส

จากตัวอย่าง / คลาสภายนอกกฎของเราค่อนข้างง่ายและคาดเดาได้ เรามีโอเปอเรเตอร์สองตัวและแต่ละตัวจะบอกเราทันทีถ้าเราจัดการกับอินสแตนซ์หรือคลาสคงที่:

  • ->- ผู้ประกอบการวัตถุ - นี้จะใช้เสมอเมื่อเราเข้าถึงอินสแตนซ์

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

    สิ่งสำคัญคือต้องทราบว่าการโทรPerson->fooไม่สมเหตุสมผล (เนื่องจากPersonเป็นคลาสไม่ใช่ตัวอย่าง) ดังนั้นจึงเป็นข้อผิดพลาดในการแยกวิเคราะห์

  • ::- scope-resolution-operator - ใช้สำหรับเข้าถึงคุณสมบัติหรือเมธอด Class แบบคงที่เสมอ

    echo Foo::bar()

    นอกจากนี้เราสามารถเรียกใช้วิธีการคงที่บนวัตถุในลักษณะเดียวกัน:

    echo $foo::bar()

    เป็นสิ่งสำคัญอย่างยิ่งที่จะต้องทราบว่าเมื่อเราทำสิ่งนี้จากภายนอกอินสแตนซ์ของวัตถุนั้นถูกซ่อนไว้จากbar()วิธีการ หมายความว่าเหมือนกับการทำงาน:

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

ดังนั้นจึง$thisไม่ได้กำหนดไว้ในสายคงที่

จากภายในอินสแตนซ์ / คลาส

สิ่งต่าง ๆ เปลี่ยนไปเล็กน้อยที่นี่ มีการใช้ตัวดำเนินการเดียวกัน แต่ความหมายจะเบลออย่างมีนัยสำคัญ

ประกอบวัตถุ ->ยังคงใช้ในการโทรให้กับวัตถุของรัฐเช่น

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

เรียกbar()วิธีการใน$foo(อินสแตนซ์ของFoo) โดยใช้วัตถุที่ผู้ประกอบการ: จะส่งผลในรุ่นอินสแตนซ์ของ$foo->bar()$a

นั่นคือสิ่งที่เราคาดหวัง

ความหมายของ::ผู้ประกอบการแม้ว่าการเปลี่ยนแปลง ขึ้นอยู่กับบริบทของการเรียกฟังก์ชั่นปัจจุบัน:

  • ภายในบริบทแบบคงที่

    ภายในบริบทแบบคงที่การโทรใด ๆ ที่ใช้::จะเป็นแบบสแตติก ลองดูตัวอย่าง:

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

    การโทรFoo::bar()จะเรียกbaz()วิธีการแบบคงที่และด้วยเหตุนี้$thisจะไม่ถูกบรรจุ เป็นที่น่าสังเกตว่าในเวอร์ชันล่าสุดของ PHP (5.3+) สิ่งนี้จะทริกเกอร์E_STRICTข้อผิดพลาดเนื่องจากเรากำลังเรียกวิธีการที่ไม่คงที่

  • ภายในบริบทของอินสแตนซ์

    ภายในบริบทอินสแตนซ์ในทางกลับกันการโทรที่ใช้โดย::ขึ้นอยู่กับผู้รับการโทร (วิธีการที่เราโทร) หากมีการกำหนดวิธีการเป็นstaticแล้วมันจะใช้การโทรคงที่ หากไม่เป็นเช่นนั้นก็จะส่งต่อข้อมูลอินสแตนซ์

    ดังนั้นการดูรหัสข้างต้นการโทร$foo->bar()จะกลับมาtrueเนื่องจากการโทร "คงที่" เกิดขึ้นภายในบริบทอินสแตนซ์

ทำให้รู้สึก? ไม่คิดอย่างนั้น มันสับสน

คำหลักสั้น

เนื่องจากการผูกทุกอย่างร่วมกันโดยใช้ชื่อคลาสค่อนข้างสกปรก PHP จึงให้คำหลัก "ทางลัด" พื้นฐาน 3 รายการเพื่อให้การแก้ไขขอบเขตทำได้ง่ายขึ้น

  • self- สิ่งนี้อ้างถึงชื่อคลาสปัจจุบัน ดังนั้นself::baz()เป็นเช่นเดียวกับFoo::baz()ในFooชั้นเรียน (วิธีการใด ๆ กับมัน)

  • parent - สิ่งนี้อ้างถึง parent ของคลาสปัจจุบัน

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

ตัวอย่าง

วิธีที่ง่ายที่สุดที่จะเข้าใจสิ่งนี้คือเริ่มดูตัวอย่าง เลือกชั้นเรียนกันเถอะ:

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

ทีนี้เราก็ดูมรดกที่นี่ด้วย ไม่สนใจสักครู่ว่านี่เป็นโมเดลวัตถุที่ไม่ดี แต่ให้ดูว่าเกิดอะไรขึ้นเมื่อเราเล่นกับสิ่งนี้:

$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

ดังนั้นตัวนับ ID จะถูกแชร์ในทั้งอินสแตนซ์และลูก (เพราะเราใช้selfเพื่อเข้าถึงถ้าเราใช้staticเราสามารถแทนที่มันในคลาสย่อย)

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

โปรดทราบว่าเรากำลังดำเนินการวิธีการPerson::getName() อินสแตนซ์ทุกครั้ง แต่เรากำลังใช้สิ่งที่parent::getName()ต้องทำในกรณีใดกรณีหนึ่ง (กรณีรอง) นี่คือสิ่งที่ทำให้วิธีการนี้มีประสิทธิภาพ

คำพูดของความระมัดระวัง # 1

โปรดทราบว่าบริบทการโทรคือสิ่งที่พิจารณาว่ามีการใช้อินสแตนซ์ ดังนั้น:

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

ไม่เป็นความจริงเสมอไป

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

ตอนนี้มันแปลกจริงๆ ที่นี่ เรากำลังเรียกระดับที่แตกต่างกัน แต่$thisที่ได้รับการส่งผ่านไปยังวิธีการเป็นตัวอย่างของFoo::isFoo()$bar

สิ่งนี้สามารถทำให้เกิดบั๊กได้ทุกประเภทและแนวคิด WTF-ery ดังนั้นผมจึงขอแนะนำให้หลีกเลี่ยงต้องการ::ผู้ประกอบการจากภายในเช่นวิธีการในสิ่งที่ยกเว้นผู้ที่เสมือน "ตัดสั้น" คำหลักที่สาม ( static, selfและparent)

คำพูดของความระมัดระวัง # 2

โปรดทราบว่าทุกคนจะใช้วิธีและคุณสมบัติแบบคงที่ นั่นทำให้พวกเขาเป็นตัวแปรระดับโลก ด้วยปัญหาเดียวกันทั้งหมดที่มากับกลม ดังนั้นฉันจะลังเลที่จะเก็บข้อมูลในวิธีการ / คุณสมบัติคงที่จนกว่าคุณจะพอใจกับการเป็นข้อมูลระดับโลกอย่างแท้จริง

คำพูดของความระมัดระวัง # 3

โดยทั่วไปคุณจะต้องการที่จะใช้สิ่งที่เรียกว่าปลายคงผูกพันโดยใช้แทนstatic selfแต่โปรดทราบว่าพวกเขาไม่เหมือนกันดังนั้นการพูดว่า "ใช้staticแทนการselfเป็นสายตาสั้นจริง ๆ แทนหยุดและคิดเกี่ยวกับการโทรที่คุณต้องการสร้างและคิดว่าถ้าคุณต้องการให้คลาสเด็กสามารถแทนที่การแก้ไขแบบคงที่ได้โทร.

TL / DR

แย่มากลองย้อนกลับไปอ่าน อาจยาวเกินไป แต่ก็นานเพราะเป็นหัวข้อที่ซับซ้อน

TL / DR # 2

ตกลงไม่เป็นไร. ในระยะสั้นselfจะใช้ในการอ้างอิงชื่อระดับปัจจุบันที่อยู่ในชั้นเรียนที่เป็น$thisหมายถึงวัตถุปัจจุบันเช่น โปรดทราบว่าselfเป็นการคัดลอก / วางทางลัด คุณสามารถแทนที่ด้วยชื่อคลาสของคุณได้อย่างปลอดภัยและมันจะทำงานได้ดี แต่$thisเป็นตัวแปรแบบไดนามิกที่ไม่สามารถระบุได้ล่วงหน้า (และอาจไม่ได้เป็นคลาสของคุณ)

TL / DR # 3

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


1
คำเตือน # 1: $ นี้จะไม่ถูกกำหนดเมื่อเรียกใช้วิธีการคงที่: 3v4l.org/9kr0e
Mark Achée

ดี ... $thisจะไม่ถูกกำหนดถ้าคุณทำตาม "มาตรฐานที่เข้มงวด" และไม่เรียกวิธีการแบบคงที่ที่ไม่ได้กำหนดเป็นแบบคงที่ ฉันเห็นผลลัพธ์ที่คุณอธิบายที่นี่: 3v4l.org/WeHVMเห็นด้วยแปลกจริง ๆ
Mark Achée

2
หลังจากอ่านคำอธิบายแบบยาวอย่างสมบูรณ์ฉันรู้สึกเกียจคร้านที่จะเลื่อนด้านบนอีกครั้งเพื่อโหวตขึ้น แค่ล้อเล่นฉันก็ลงคะแนนแล้ว: D ขอบคุณสิ่งนี้มีประโยชน์มาก
Mr_Green

3
จะดีที่จะเพิ่มคำอธิบายที่ชัดเจนเกี่ยวกับความแตกต่างระหว่างตัวเอง :: $ คุณสมบัติและตัวเอง :: คุณสมบัติ; ฉันคิดว่ามันค่อนข้างสับสนเช่นกัน
Tommaso Barbugli

1
WoC # 1 ทำงานแตกต่างจาก PHP 7 ตามที่Foo::isFoo()เรียกว่าแบบสแตติก$thisจะไม่ถูกกำหนด นั่นเป็นพฤติกรรมที่ใช้งานง่ายในความคิดของฉัน - อีกผลที่แตกต่างกันจะได้รับหากมีการขยายจากBar Fooจากนั้นการโทรFoo::isFoo()จะเป็นจริงในบริบทอินสแตนซ์ (ไม่เฉพาะ PHP7)
Kontrollfreak

117

self(ไม่ใช่ $ self) หมายถึงประเภทของคลาสโดยที่$thisอ้างอิงถึงอินสแตนซ์ปัจจุบันของคลาส selfสำหรับใช้ในฟังก์ชั่นสมาชิกแบบคงที่เพื่อให้คุณสามารถเข้าถึงตัวแปรสมาชิกแบบคงที่ $thisใช้ในฟังก์ชันสมาชิกแบบไม่คงที่และเป็นการอ้างอิงถึงอินสแตนซ์ของคลาสที่เรียกใช้ฟังก์ชันสมาชิก

เนื่องจากthisเป็นวัตถุคุณจึงใช้มันเหมือน:$this->member

เนื่องจากselfไม่ใช่วัตถุจึงเป็นชนิดที่อ้างอิงถึงคลาสปัจจุบันโดยอัตโนมัติคุณจึงใช้มันเหมือน:self::member


97

$this-> ใช้เพื่ออ้างถึงอินสแตนซ์เฉพาะของตัวแปรคลาส (ตัวแปรสมาชิก) หรือวิธีการ

Example: 
$derek = new Person();

$ derek ตอนนี้เป็นตัวอย่างเฉพาะของบุคคล ทุกคนมีชื่อและนามสกุลเป็นนามสกุล แต่ $ derek มีชื่อและนามสกุลเฉพาะ (ดีเร็กมาร์ติน) ภายในอินสแตนซ์ $ derek เราสามารถอ้างถึงสิ่งเหล่านี้เป็น $ this-> first_name และ $ this-> last_name

ClassName :: ใช้เพื่ออ้างถึงชนิดของคลาสนั้นและตัวแปรสแตติกวิธีการสแตติก หากช่วยได้คุณสามารถแทนที่คำว่า "คงที่" ด้วย "แบ่งปัน" ได้ เนื่องจากพวกเขาแชร์กันพวกเขาไม่สามารถอ้างถึง $ this ซึ่งอ้างถึงอินสแตนซ์เฉพาะ (ไม่แชร์) ตัวแปรแบบคงที่ (เช่น $ db_connection คงที่) สามารถใช้ร่วมกันระหว่างอินสแตนซ์ทั้งหมดของชนิดของวัตถุ ตัวอย่างเช่นวัตถุฐานข้อมูลทั้งหมดแชร์การเชื่อมต่อเดียว (การเชื่อมต่อ $ แบบคงที่)

ตัวอย่างตัวแปรแบบคงที่: แกล้งทำเป็นว่าเรามีคลาสฐานข้อมูลที่มีตัวแปรสมาชิกเดียว: $ num_connections แบบคงที่; ตอนนี้ให้ใส่ไว้ในตัวสร้าง:

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

เช่นเดียวกับวัตถุที่มีคอนสตรัคเตอร์พวกเขายังมี destructors ซึ่งจะดำเนินการเมื่อวัตถุตายหรือไม่ได้ตั้งค่า:

function __destruct()
{
    $num_connections--;
}

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

echo DB::num_connections;

เนื่องจาก $ num_connections เป็นแบบคงที่ (ใช้ร่วมกัน) มันจะแสดงจำนวนทั้งหมดของวัตถุฐานข้อมูลที่ใช้งานอยู่ คุณอาจเห็นเทคนิคนี้ใช้เพื่อแบ่งปันการเชื่อมต่อฐานข้อมูลระหว่างอินสแตนซ์ทั้งหมดของคลาสฐานข้อมูล สิ่งนี้เสร็จสิ้นเนื่องจากการสร้างการเชื่อมต่อฐานข้อมูลใช้เวลานานดังนั้นจึงเป็นการดีที่สุดที่จะสร้างเพียงหนึ่งรายการและใช้ร่วมกัน (ซึ่งเรียกว่ารูปแบบซิงเกิล)

วิธีการแบบคงที่ (เช่นมุมมองแบบคงที่สาธารณะ :: format_phone_number ($ หลัก)) สามารถใช้ได้โดยไม่ต้องให้อินสแตนซ์แรกของวัตถุเหล่านั้น (เช่นพวกเขาไม่ได้อ้างถึง $ this ภายใน)

ตัวอย่างวิธีการแบบคงที่:

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

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

อย่างที่คุณสามารถเห็นฟังก์ชั่นสาธารณะคงที่ prettyName ไม่รู้อะไรเกี่ยวกับวัตถุ เป็นเพียงการทำงานกับพารามิเตอร์ที่คุณส่งผ่านเช่นฟังก์ชั่นปกติที่ไม่ได้เป็นส่วนหนึ่งของวัตถุ ถ้าอย่างนั้นทำไมเราถึงไม่ได้มันเป็นส่วนหนึ่งของวัตถุล่ะ?

  1. ก่อนอื่นการแนบฟังก์ชั่นเข้ากับวัตถุจะช่วยให้คุณจัดระเบียบสิ่งต่าง ๆ ได้เพื่อให้คุณรู้ว่าจะหาได้ที่ไหน
  2. ประการที่สองจะป้องกันการตั้งชื่อความขัดแย้ง ในโครงการขนาดใหญ่คุณมีแนวโน้มที่จะมีสองนักพัฒนาสร้างฟังก์ชั่น getName () หากหนึ่งสร้าง ClassName1 :: getName () และอื่น ๆ สร้าง ClassName2 :: getName () มันจะไม่มีปัญหาเลย ไม่มีความขัดแย้ง Yay วิธีคงที่!

SELF :: ถ้าคุณกำลังเขียนโค้ดนอกวัตถุที่มีวิธีการคงที่ที่คุณต้องการอ้างถึงคุณต้องเรียกมันโดยใช้ชื่อของวัตถุ View :: format_phone_number ($ phone_number); หากคุณกำลังเข้ารหัสภายในวัตถุที่มีวิธีการแบบคงที่คุณต้องการที่จะอ้างถึงคุณสามารถทั้งใช้วัตถุชื่อ View :: format_phone_number ($ PN) หรือคุณสามารถใช้ตัวเอง :: format_phone_number ($ PN) ทางลัด

สิ่งเดียวกันนี้สำหรับตัวแปรแบบคงที่: ตัวอย่าง:ดู :: templates_path และ self :: templates_path

ภายในคลาส DB ถ้าเราอ้างถึงวิธีการคงที่ของวัตถุอื่น ๆ เราจะใช้ชื่อของวัตถุ: ตัวอย่าง: Session :: getUsersOnline ();

แต่ถ้าคลาส DB ต้องการอ้างถึงตัวแปรสแตติกของตัวเองมันก็จะพูดตัวเอง: ตัวอย่าง:การเชื่อมต่อด้วยตนเอง ::;

หวังว่าจะช่วยให้ชัดเจนขึ้น :)


คำตอบที่ดี ฉันต้องการชี้ให้เห็นเมื่ออ้างอิงถึงแอตทริบิวต์คงที่คุณต้องใช้$เครื่องหมาย ตัวอย่างเช่นself::$templates_path
henrywright

30

จากโพสต์บล็อกนี้ :

  • self หมายถึงคลาสปัจจุบัน
  • self สามารถใช้เรียกฟังก์ชันแบบสแตติกและอ้างอิงตัวแปรสมาชิกแบบสแตติก
  • self สามารถใช้ภายในฟังก์ชั่นคงที่
  • self ยังสามารถปิดพฤติกรรม polymorphic โดยการข้าม vtable
  • $this อ้างถึงวัตถุปัจจุบัน
  • $this สามารถใช้เรียกฟังก์ชันคงที่ได้
  • $thisไม่ควรใช้เพื่อเรียกตัวแปรสมาชิกแบบคงที่ ใช้selfแทน
  • $this ไม่สามารถใช้ภายในฟังก์ชั่นคงที่

26

ใน PHP คุณใช้คำสำคัญด้วยตนเองเพื่อเข้าถึงคุณสมบัติและวิธีการแบบคงที่

ปัญหาคือคุณสามารถแทนที่$this->method()ด้วยself::method()ที่ใดก็ได้โดยไม่คำนึงว่าmethod()จะประกาศคงที่หรือไม่ คุณควรใช้อันไหนดี?

พิจารณารหัสนี้:

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

ในตัวอย่างนี้self::who()จะส่งออก 'ผู้ปกครอง' เสมอในขณะที่$this->who()จะขึ้นอยู่กับสิ่งที่วัตถุมี

ตอนนี้เราจะเห็นได้ว่าตัวเองหมายถึงระดับที่จะเรียกว่าในขณะที่$thisหมายถึงระดับของวัตถุในปัจจุบัน

ดังนั้นคุณควรใช้ตัวเองเฉพาะเมื่อ$thisไม่พร้อมใช้งานหรือเมื่อคุณไม่ต้องการอนุญาตให้คลาสที่สืบทอดเพื่อเขียนทับวิธีปัจจุบัน


22

ภายในคำจำกัดความของคลาส$thisหมายถึงวัตถุปัจจุบันในขณะที่selfอ้างอิงถึงคลาสปัจจุบัน

มันเป็นสิ่งจำเป็นที่จะอ้างถึงองค์ประกอบชั้นเรียนโดยใช้และอ้างถึงองค์ประกอบวัตถุโดยใช้self$this

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

21

นี่คือตัวอย่างของการใช้งาน $ this และ self สำหรับตัวแปรสมาชิกแบบไม่คงที่และแบบคงที่:

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

ตามhttp://www.php.net/manual/en/language.oop5.static.php$selfไม่มี มีเพียง$thisเพื่ออ้างอิงถึงอินสแตนซ์ปัจจุบันของคลาส (วัตถุ) และตัวเองซึ่งสามารถใช้เพื่ออ้างถึงสมาชิกแบบคงที่ของคลาส ความแตกต่างระหว่างอินสแตนซ์ของวัตถุและคลาสเข้ามาที่นี่


9
คำแนะนำ: อ่านคำตอบนี้เมื่อหยุดกรด
a20

16

ClassName::staticMemberผมเชื่อว่าคำถามไม่ได้ว่าคุณสามารถโทรหาสมาชิกแบบคงที่ของการเรียนโดยการเรียก คำถามคือสิ่งที่แตกต่างระหว่างการใช้และself::classmember$this->classmember

ตัวอย่างเช่นทั้งสองตัวอย่างต่อไปนี้ทำงานโดยไม่มีข้อผิดพลาดไม่ว่าคุณจะใช้self::หรือ$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;
    }
}

เป็นเรื่องตลกโดยเฉพาะอย่างยิ่งที่คุณเริ่มต้นคำตอบด้วย "ฉันเชื่อว่าคำถามไม่ใช่ว่าคุณสามารถโทรหาสมาชิกแบบคงที่ของชั้นเรียนได้ด้วยการเรียก ClassName :: staticMember คำถามคือความแตกต่างระหว่างการใช้ตัวเอง :: classmember และ $ this-> classmember" จากนั้นคุณดำเนินการต่อเพื่อแสดงความแตกต่างไม่ได้เลย ที่จริงแล้วคุณแสดงตัวอย่างว่าตัวเลือกทั้งสองทำงานอย่างไรเหมือนกัน -1
Buttle Butkus

อย่างไรก็ตามมีประโยชน์ ขอบเขตเกี่ยวกับความละเอียดและส่วนนี้ไม่ชัดเจนในคู่มือ php ฉันยังพบว่ามันมีประโยชน์เต็ม
renoirb

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

16

self หมายถึงคลาสปัจจุบัน (ซึ่งเรียกว่า)

$thisอ้างถึงวัตถุปัจจุบัน คุณสามารถใช้สแตติกแทนตนเอง ดูตัวอย่าง:

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

เอาท์พุท: ผู้ปกครองเด็ก


16
  • ตัวชี้วัตถุ$thisที่อ้างถึงวัตถุปัจจุบัน
  • ค่าระดับstaticหมายถึงวัตถุปัจจุบัน
  • ค่าคลาสselfหมายถึงคลาสที่แน่นอนที่กำหนดไว้
  • ค่าคลาสparentหมายถึงพาเรนต์ของคลาสที่แน่นอนที่ถูกกำหนด

ดูตัวอย่างต่อไปนี้ซึ่งแสดงการโอเวอร์โหลด

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

ส่วนใหญ่เวลาที่คุณต้องการที่จะดูที่ระดับปัจจุบันซึ่งเป็นเหตุผลที่คุณใช้หรือstatic $thisอย่างไรก็ตามมีบางครั้งที่คุณต้องการ selfเพราะคุณต้องการชั้นเรียนดั้งเดิมโดยไม่คำนึงถึงสิ่งที่ขยาย (มากไม่ค่อยมาก)


14

อย่างที่ไม่มีใครพูดถึงเกี่ยวกับการแสดงนี่เป็นเกณฑ์มาตรฐานขนาดเล็กที่ฉันทำ (5.6):

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

นี่คือผลลัพธ์สำหรับการวิ่ง 2,000 000 และนี่คือรหัสที่ฉันใช้:

<?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
ฟังก์ชั่น no-op 2,000 000 ครั้งใช้งานได้ 1 วินาที ต้องรัก PHP
rr-

PHP เก่าดี :) แต่โทร = 0.001ms มันแย่ขนาดนั้นเหรอ?
tleb

ฉันเชื่อว่าสิ่งนี้ (และสิ่งที่คล้ายกัน) คือสาเหตุที่สิ่งต่าง ๆ เช่น ORM รู้สึกช้าถ้าคุณไม่แคชสิ่งและตัวสร้างไซต์แบบคงที่เป็นสิ่ง
rr-

2
ในทางทฤษฎีแล้วควรใช้วงจรนาฬิกาตัวประมวลผล 1 รอบซึ่งทำให้เกิดขึ้นใน1 / 2e9 s = 0.5 nsวันนี้
Buddy

แค่อ่านคำตอบของฉันอีกครั้ง ระวัง: มันสร้างคลาสด้วย ฉันไม่รู้ว่าทำไมฉันไม่ใช้useคำหลัก tbh แต่ฉันไม่มี PHP อีกต่อไปที่จะทำซ้ำมาตรฐานและฉันไม่รู้สึกอยากติดตั้งใหม่
tleb

13

เมื่อselfใช้กับ::โอเปอเรเตอร์มันหมายถึงคลาสปัจจุบันซึ่งสามารถทำได้ทั้งในบริบทคงที่และไม่คงที่ $thisหมายถึงวัตถุนั้นเอง นอกจากนี้มันเป็นกฎหมายที่สมบูรณ์แบบที่จะใช้$thisเพื่อเรียกวิธีการคงที่ (แต่ไม่ได้อ้างถึงเขตข้อมูล)


8

ฉันพบคำถามเดียวกันและคำตอบง่ายๆคือ:

  • $this ต้องการอินสแตนซ์ของคลาส
  • self:: ไม่

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


7

$this หมายถึงวัตถุชั้นปัจจุบัน selfหมายถึงคลาสปัจจุบัน (ไม่ใช่วัตถุ) คลาสเป็นพิมพ์เขียวของวัตถุ ดังนั้นคุณจึงกำหนดคลาส แต่คุณสร้างวัตถุ

ดังนั้นในคำอื่น ๆ ที่ใช้งานและself for staticthis for none-static members or methods

ในสถานการณ์ที่เด็ก / ผู้ปกครองself / parentส่วนใหญ่จะใช้เพื่อระบุเด็กและผู้ปกครองสมาชิกระดับและวิธีการ


7

นอกจากนี้ตั้งแต่$this::ยังไม่ได้พูดคุย

เพื่อจุดประสงค์ในการให้ข้อมูลเท่านั้น PHP 5.3 เมื่อจัดการกับออบเจ็กต์อินสแตนซ์เพื่อรับค่าขอบเขตปัจจุบันซึ่งต่างจากการใช้static::งานคุณสามารถเลือกใช้$this::เช่นนั้นได้

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

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

นอกจากนี้ยังแสดงถึงการใช้$object::CONSTANTตัวอย่างเช่นecho $foo::NAME;เมื่อเทียบกับ$this::NAME;


5

ใช้selfถ้าคุณต้องการเรียกเมธอดของคลาสโดยไม่สร้างวัตถุ / อินสแตนซ์ของคลาสนั้นดังนั้นจึงช่วยประหยัดRAM (บางครั้งใช้ตัวเองเพื่อจุดประสงค์นั้น) กล่าวอีกนัยหนึ่งมันคือการเรียกวิธีการแบบสแตติก ใช้thisสำหรับมุมมองวัตถุ


2

กรณีที่ 1: การใช้selfสามารถใช้สำหรับค่าคงที่คลาสได้

 คลาส classA { 
     const FIXED_NUMBER = 4; 
     ตนเอง :: POUNDS_TO_KILOGRAMS
}

ถ้าคุณต้องการโทรหามันนอกห้องเรียนใช้classA::POUNDS_TO_KILOGRAMSเพื่อเข้าถึงค่าคงที่

กรณีที่ 2: สำหรับคุณสมบัติคงที่

คลาส classC {
     ฟังก์ชั่นสาธารณะ __ โครงสร้าง () { 
     ตนเอง :: _ $ เคาน์เตอร์ ++; $ this-> num = self :: $ _ counter;
   }
}

1

ตาม php.net มีสามคำพิเศษในบริบทนี้: self, และparent staticพวกมันถูกใช้เพื่อเข้าถึงคุณสมบัติหรือเมธอดจากภายในนิยามคลาส

$thisในทางตรงกันข้ามจะใช้ในการเรียกตัวอย่างและวิธีการของชั้นเรียนใด ๆ ตราบเท่าที่ชั้นนั้นสามารถเข้าถึงได้


-1

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

คุณสามารถใช้คำสำคัญself ::ในชั้นเรียนอื่นและเข้าถึงสมาชิกคงที่วิธีการและค่าคงที่ เมื่อมันจะถูกขยายจากระดับผู้ปกครองและเหมือนกันในกรณีของ$คำหลักนี้ คุณสามารถเข้าถึงสมาชิกที่ไม่คงที่วิธีการและฟังก์ชั่นในชั้นเรียนอื่นเมื่อมันจะถูกขยายจากชั้นผู้ปกครอง

รหัสที่ระบุด้านล่างเป็นตัวอย่างของตัวเอง ::และ$คำหลักนี้ เพียงคัดลอกและวางรหัสในไฟล์รหัสของคุณและดูผลลัพธ์

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