PHP Fatal error: การใช้ $ this เมื่อไม่ได้อยู่ในบริบทของวัตถุ


138

ฉันมีปัญหา:

ฉันกำลังเขียน WebApp ใหม่โดยไม่มี Framework

ในindex.phpของฉันฉันใช้:require_once('load.php');

และในload.phpฉันใช้require_once('class.php');ในการโหลดของฉันclass.php

ในclass.phpของฉันฉันพบข้อผิดพลาดนี้:

ข้อผิดพลาดร้ายแรง: การใช้ $ this เมื่อไม่อยู่ในบริบทของวัตถุใน class.php บนบรรทัด ... (ในตัวอย่างนี้จะเป็น 11)

ตัวอย่างการเขียนclass.phpของฉัน:

class foobar {

    public $foo;

    public function __construct() {
        global $foo;

        $this->foo = $foo;
    }

    public function foobarfunc() {
        return $this->foo();
    }

    public function foo() {
        return $this->foo;
    }
}

ในindex.phpของฉันฉันกำลังโหลดอาจเป็นfoobarfunc()เช่นนี้:

foobar::foobarfunc();

แต่ยังสามารถ

$foobar = new foobar;
$foobar->foobarfunc();

เหตุใดจึงเกิดข้อผิดพลาด


2
บังเอิญฉันกำลังดิ้นรนกับข้อผิดพลาดนี้ประมาณ 3 ชั่วโมงเมื่อวานนี้! :)
แจ็ค

คำตอบ:


184

ใน index.php ของฉันฉันกำลังโหลด foobarfunc () เช่นนี้:

 foobar::foobarfunc();  // Wrong, it is not static method

แต่ยังสามารถ

$foobar = new foobar;  // correct
$foobar->foobarfunc();

คุณไม่สามารถเรียกใช้วิธีนี้ได้เนื่องจากไม่ใช่วิธีการแบบคงที่

foobar::foobarfunc();

คุณควรใช้:

foobar->foobarfunc();

อย่างไรก็ตามหากคุณได้สร้างวิธีการแบบคงที่เช่น:

static $foo; // your top variable set as static

public static function foo() {
    return self::$foo;
}

จากนั้นคุณสามารถใช้สิ่งนี้:

foobar::foobarfunc();

1
ตัวแปรที่มีชื่อเดียวกันไม่ใช่ปัญหา $this->fooเป็นสมาชิกคลาสในขณะที่$fooเป็นเพียงตัวแปรในขอบเขตฟังก์ชัน (นำเข้าจากขอบเขตส่วนกลาง) ชื่อฟังก์ชันที่มีชื่อเดียวกับสมาชิกก็ไม่ใช่ปัญหาเช่นกัน
Gordon

157
คุณไม่สามารถใช้$thisในวิธีการคงที่
Yacoby

5
เป็นเรื่องตลกที่คำตอบที่ผิดอย่างสิ้นเชิงทำให้คะแนนโหวตสูงขึ้น $ นี้ไม่สามารถใช้ได้ในบริบทของชั้นเรียน OP จะได้รับข้อผิดพลาดเดียวกันจากตัวอย่างด้านบน
Gordon

4
@Sarfraz ไม่มีความผิด แต่ก็ยังผิด คุณสามารถเรียกวิธีการอินสแตนซ์ด้วย::. มันผิดE_STRICTแต่มันไม่$thisทำงานตราบเท่าที่ร่างกายวิธีการที่ไม่อ้างอิงขอบเขตตัวอย่างเช่นการใช้งาน นอกจากนี้ยังจะได้ชี้ไปที่self::foo $this->fooมันอ้างอิงระดับคงที่ ทั้งสองอย่างself::fooและself::$fooจะทำให้เกิดข้อผิดพลาดร้ายแรง
Gordon

3
@Sarfraz มันดีขึ้นแล้ว ขออภัยที่รบกวนคุณ แต่เนื่องจากนี่เป็นคำตอบที่ยอมรับได้ฉันจึงคิดว่าจำเป็นต้องชี้ให้เห็นสิ่งเหล่านี้ :) ขอขอบคุณที่อดทนรอ
Gordon

27

คุณกำลังเรียกใช้วิธีการไม่คงที่:

public function foobarfunc() {
    return $this->foo();
}

การใช้การโทรแบบคงที่:

foobar::foobarfunc();

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

ดังนั้น:

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


ที่นี่เมธอดของชั้นเรียนของคุณกำลังใช้อินสแตนซ์ปัจจุบันของคลาสเนื่องจากจำเป็นต้องเข้าถึงไฟล์ $fooคุณสมบัติของคลาส

ซึ่งหมายความว่าวิธีการของคุณต้องการอินสแตนซ์ของคลาสซึ่งหมายความว่าไม่สามารถคงที่ได้

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

$foobar = new foobar();
$foobar->foobarfunc();


สำหรับข้อมูลเพิ่มเติมอย่าลังเลที่จะอ่านในคู่มือ PHP:


โปรดทราบว่าคุณอาจไม่ต้องการบรรทัดนี้ใน__constructวิธีการของคุณ:

global $foo;

การใช้globalคีย์เวิร์ดจะทำให้$fooตัวแปรถูกประกาศนอกฟังก์ชันและคลาสทั้งหมดสามารถมองเห็นได้จากภายในเมธอดนั้น ... และคุณอาจไม่มี$fooตัวแปรดังกล่าว

ในการเข้าถึง$foo คุณสมบัติคลาสคุณจะต้องใช้$this->fooเช่นเดียวกับที่คุณทำ


11

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

หากคุณเปิดใช้E_STRICTงาน PHP จะแจ้งประกาศเกี่ยวกับสิ่งนี้:

Strict Standards: 
Non-static method foobar::foobarfunc() should not be called statically

ทำสิ่งนี้แทน

$fb = new foobar;
echo $fb->foobarfunc();

ในด้านข้างฉันไม่แนะนำให้ใช้globalในชั้นเรียนของคุณ หากคุณต้องการบางสิ่งจากภายนอกในชั้นเรียนของคุณให้ส่งผ่านตัวสร้าง สิ่งนี้เรียกว่าDependency Injectionและจะทำให้โค้ดของคุณสามารถบำรุงรักษาได้มากขึ้นและพึ่งพาสิ่งภายนอกน้อยลง


6

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

ดังนั้นเมื่อคุณเรียกใช้ฟังก์ชันคลาสเช่น foobar :: foobarfunc () อ็อบเจ็กต์จะไม่ถูกสร้างขึ้น แต่ภายในฟังก์ชันนั้นคุณเขียนกลับ $ this-> foo () ตอนนี้ $ นี่คืออะไร นั่นเป็นเหตุผลว่าทำไมมันถึงใช้ $ this เมื่อไม่ได้อยู่ในบริบทของวัตถุใน class.php

Solutions:

  1. สร้างวัตถุและเรียก foobarfunc ()

  2. เรียก foo () โดยใช้ชื่อคลาสภายใน foobarfunc ()


2
หรือแค่ใช้ self :: แทน $ this
Motassem MK

4

เมื่อคุณเรียกใช้ฟังก์ชันในบริบทคงที่$thisจะไม่มีอยู่จริง

คุณจะต้องใช้this::xyz()แทน

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


4

วิธีการที่รวดเร็ว: (foobar ใหม่ ()) -> foobarfunc ();

คุณต้องโหลดคลาสของคุณแทนที่:

foobar::foobarfunc();

โดย:

(new foobar())->foobarfunc();

หรือ :

$Foobar = new foobar();
$Foobar->foobarfunc();

หรือทำให้คงที่foobar::ฟังก์ชันการใช้

class foobar {
    //...

    static function foobarfunc() {
        return $this->foo();
    }
}

0

$foobar = new foobar;ใส่ชั้น foobar ใน $ foobar, ไม่วัตถุ ในการรับวัตถุคุณต้องเพิ่มวงเล็บ:$foobar = new foobar();

ข้อผิดพลาดของคุณคือการที่คุณเรียกใช้เมธอดบนคลาสดังนั้นจึงไม่มี$thisเนื่องจาก$thisมีอยู่ในวัตถุเท่านั้น


0

ดูเหมือนว่าฉันจะเป็นบั๊กใน PHP ข้อผิดพลาด

'ข้อผิดพลาดร้ายแรง: ข้อผิดพลาดที่ไม่ถูกจับ: การใช้ $ นี้เมื่อไม่ได้อยู่ในบริบทของวัตถุใน'

ปรากฏในฟังก์ชันโดยใช้$thisแต่ข้อผิดพลาดคือฟังก์ชันการโทรกำลังใช้ฟังก์ชันไม่คงที่เป็นแบบคงที่ เช่น:

Class_Name
{
    function foo()
    {
        $this->do_something(); // The error appears there.
    }
    function do_something()
    {
        ///
    }
}

ในขณะที่ข้อผิดพลาดอยู่ที่นี่:

Class_Name::foo();

-2

เพียงใช้วิธีการคลาสโดยใช้สิ่งนี้ foobar->foobarfunc();


2
โปรดตอบคำถามเก่าหากคุณมีสิ่งใหม่ที่จะเพิ่มเท่านั้น
Ajean
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.