เรียกวิธีการคงที่ภายในชั้นเรียนหรือไม่?


166

ฉันจะเรียกวิธีการคงที่จากวิธีอื่นภายในชั้นเรียนเดียวกันได้อย่างไร

$this->staticMethod();

หรือ

$this::staticMethod();

13
คุณอาจสนใจสิ่งนี้ ( selfกับ$this): stackoverflow.com/questions/151969/php-self-vs-this
Felix Kling

เพียงแค่ FYI ตัวอย่างแรกของคุณคือตัวแปรอินสแตนซ์ที่เรียกใช้วิธีสแตติกซึ่งเป็นไปไม่ได้เนื่องจากวิธีสแตติกเป็นส่วนหนึ่งของคลาสและไม่สามารถเข้าถึงได้ผ่านตัวแปรอินสแตนซ์
joejoeson

คุณสามารถลบ $ this ได้ในตอนนี้โปรดใช้ไม่ได้หากใช้วิธีการคงที่เท่านั้นและไม่มีอินสแตนซ์อยู่
malhal

คำตอบ:


322

... แต่ทำไม $ this-> staticMethod () ทำงานเกินไป คุณช่วยอธิบายได้ไหมว่าทำไม :: staticMethod () ตนเองที่ถูกต้องมากขึ้น (ถ้าเป็น)
Ian Dunn

29
@ Ian Dunn ใส่เพียง$thisมีอยู่ถ้าวัตถุได้รับการยกตัวอย่างและคุณสามารถใช้$this->methodจากภายในวัตถุที่มีอยู่เท่านั้น ถ้าคุณมีวัตถุ self::แต่เพียงโทรวิธีการแบบคงที่และในวิธีการที่คุณต้องการที่จะเรียกวิธีการแบบคงที่อื่นในระดับเดียวกันคุณต้องใช้ ดังนั้นเพื่อหลีกเลี่ยงข้อผิดพลาดที่อาจเกิดขึ้น (และคำเตือนอย่างเคร่งครัด) selfมันจะดีกว่าที่จะใช้
jeroen

1
ขอบคุณ! ใน Laravel ผมพบว่าผมไม่ได้ตั้งใจโทรวิธีสถิตทั่วตัวควบคุมการขยายการใช้แต่พื้นผิวที่มีปัญหาไม่ได้จนกว่ารหัสได้รับการผลักดันให้$this ไม่มีข้อผิดพลาดกลับมาคุ้มค่าเป็นเพียงstage 0ระวังด้วยสิ่งนี้ใช้self::
blamb

44

สมมติว่านี่คือคลาสของคุณ:

class Test
{
    private $baz = 1;

    public function foo() { ... }

    public function bar() 
    {
        printf("baz = %d\n", $this->baz);
    }

    public static function staticMethod() { echo "static method\n"; }
}

จากภายในfoo()วิธีลองดูที่ตัวเลือกต่างๆ:

$this->staticMethod();

เพื่อที่จะเรียกstaticMethod()ว่าเป็นวิธีการอินสแตนซ์ใช่มั้ย มันไม่ใช่. นี่เป็นเพราะวิธีการได้รับการประกาศเป็นpublic staticล่ามจะเรียกมันว่าเป็นวิธีการแบบคงที่ดังนั้นมันจะทำงานตามที่คาดไว้ อาจเป็นที่ถกเถียงกันอยู่ว่าการทำเช่นนั้นทำให้เห็นได้ชัดน้อยลงจากรหัสที่มีการเรียกใช้เมธอดแบบคงที่

$this::staticMethod();

ตั้งแต่ PHP 5.3 คุณสามารถใช้$var::method()เพื่อหมายถึง<class-of-$var>::; นี่ค่อนข้างสะดวกแม้ว่ากรณีการใช้งานด้านบนยังค่อนข้างแปลก ดังนั้นสิ่งนี้จึงนำเราไปสู่วิธีการทั่วไปในการเรียกใช้เมธอดแบบสแตติก:

self::staticMethod();

ตอนนี้ก่อนที่คุณจะเริ่มคิดว่า::เป็นผู้ประกอบการคงเรียกร้องให้ฉันให้คุณอีกตัวอย่างหนึ่ง:

self::bar();

นี้จะพิมพ์baz = 1ซึ่งหมายความว่า$this->bar()และself::bar()ทำสิ่งเดียวกัน; นั่นเป็นเพราะ::เป็นเพียงผู้ดำเนินการแก้ไขปัญหาขอบเขต มันจะทำให้มีparent::, self::และstatic::การทำงานและให้คุณสามารถเข้าถึงตัวแปรคงที่; วิธีการเรียกใช้ขึ้นอยู่กับลายเซ็นและวิธีการโทรที่ถูกเรียก

หากต้องการดูทั้งหมดนี้ในการดำเนินการให้ดูที่การส่งออก 3v4l.org นี้


self::bar()ดูเหมือนจะทำให้เข้าใจผิด - ตอนนี้เลิกใช้แล้วหรือยัง? (ใช้self::เพื่อเรียกวิธีการอินสแตนซ์แทนที่จะเป็นวิธีแบบคงที่)
ToolmakerSteve

@ToolmakerSteve คุณจะบอกว่ามันเป็นวิธีที่ทำให้เข้าใจผิด?
Ja͢ck

การพูดอย่างมีเหตุผลไม่มีselfเมื่อเรียกวิธีการคงที่ ตามคำจำกัดความ: วิธีการคงที่สามารถเรียกได้จากทุกที่และไม่ได้รับพารามิเตอร์ "ตัวเอง" อย่างไรก็ตามผมเห็นความสะดวกสบายของว่าไวยากรณ์เพื่อที่คุณจะได้ไม่ต้องเขียนphp MyClassName::ฉันคุ้นเคยกับภาษาที่พิมพ์แบบคงที่ซึ่งคอมไพเลอร์จะต้องได้รับตัวแปรทั้งหมดที่มีอยู่ในขอบเขตปัจจุบันดังนั้น (สามารถเทียบเท่า) self::สามารถละเว้น ดังนั้นคนเดียวเท่านั้นพูดself instanceMethod; self staticMethodไม่มีเหตุผลที่จะบอกว่า
ToolmakerSteve

15

นี่เป็นการตอบกลับที่ช้ามาก แต่เพิ่มรายละเอียดเกี่ยวกับคำตอบก่อนหน้า

เมื่อพูดถึงการเรียกใช้เมธอดสแตติกใน PHP จากวิธีสแตติกอื่นในคลาสเดียวกันสิ่งสำคัญคือการแยกความแตกต่างระหว่างselfและชื่อคลาส

ยกตัวอย่างโค้ดนี้:

class static_test_class {
    public static function test() {
        echo "Original class\n";
    }

    public static function run($use_self) {
        if($use_self) {
            self::test();
        } else {
            $class = get_called_class();
            $class::test(); 
        }
    }
}

class extended_static_test_class extends static_test_class {
    public static function test() {
        echo "Extended class\n";
    }
}

extended_static_test_class::run(true);
extended_static_test_class::run(false);

ผลลัพธ์ของรหัสนี้คือ:

ชั้นเรียนดั้งเดิม

ชั้นเรียนขยาย

นี้เป็นเพราะ selfหมายถึงคลาสที่มีโค้ดอยู่แทนที่จะเป็นคลาสของโค้ดที่ถูกเรียกใช้

หากคุณต้องการใช้วิธีที่กำหนดไว้ในคลาสที่สืบทอดคลาสดั้งเดิมคุณต้องใช้สิ่งต่อไปนี้:

$class = get_called_class();
$class::function_name(); 

2
ฉันพบข้อมูลนี้แล้ว เล็ก ๆ น้อย ๆ ฉันจะไม่พูดว่าคำตอบอื่น ๆ คือ "ทำให้เข้าใจผิด" แม่นยำกว่าที่จะบอกว่าพวกเขา "ไม่สมบูรณ์"; พวกเขาไม่ได้ตอบคำถาม (ไม่ได้ถาม) เกี่ยวกับสิ่งที่self::เกิดขึ้นในกรณี (หายาก) ซึ่งวิธีการแบบคงที่ A เรียกวิธีการแบบคงที่อีกแบบ B และ B ถูกแทนที่ในคลาสย่อย IMHO มันมีความสับสนน้อยกว่าในการ จำกัด วิธีการแทนที่ "วิธี" ตัวอย่าง ใช้ความสามารถนั้นเท่าที่จำเป็นในระดับคงที่ ใส่อีกวิธีหนึ่งผู้อ่านรหัสของคุณคาดหวังว่าวิธีการแทนที่วิธีการอินสแตนซ์ (นั่นคือสาระสำคัญของการเข้ารหัส OO) แต่ไม่ใช่ของแบบคงที่
ToolmakerSteve

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

2

ในเวอร์ชัน PHP ต่อมา self::staticMethod();ก็จะไม่ทำงาน มันจะโยนข้อผิดพลาดมาตรฐานที่เข้มงวด

ในกรณีนี้เราสามารถสร้างวัตถุของคลาสเดียวกันและเรียกตามวัตถุ

นี่คือตัวอย่าง

class Foo {

    public function fun1() {
        echo 'non-static';   
    }

    public static function fun2() {
        echo (new self)->fun1();
    }
}

คุณสามารถทำได้แม้ว่าfun1จะไม่ได้ใช้selfมันก็ไม่ได้เป็นเหตุผลที่จะทำให้มันเป็นวิธีการ วิธีการที่เหมาะสมที่จะทำเช่นนี้ใน PHP คือการประกาศนั้นเรียกโดยระบุคลาส:public static function fun1 Foo::fun1ฉันมั่นใจว่าเป็นวิธีที่ตั้งใจในการแก้ไขข้อผิดพลาดมาตรฐานที่เข้มงวด
ToolmakerSteve
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.