การอ้างอิง: ขอบเขตตัวแปรคืออะไรตัวแปรใดบ้างที่สามารถเข้าถึงได้จากที่ไหนและอะไรคือข้อผิดพลาด“ ตัวแปรที่ไม่ได้กำหนด”


167

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

"ขอบเขตตัวแปร" ใน PHP คืออะไร? ตัวแปรจากไฟล์. php หนึ่งสามารถเข้าถึงได้ในอีกไฟล์หนึ่งหรือไม่ เหตุใดฉันจึงได้รับข้อผิดพลาด"ตัวแปรที่ไม่ได้กำหนด"


1
หากคุณตั้งชื่อนี้ว่า "ตัวแปรไม่ได้นิยาม" คุณจะได้รับความนิยมเพิ่มขึ้น :) ทำได้ดี แต่
Dale

@ Dale, ไม่จริง มุมมอง 2k ใน 2 ปีคือ ....
Pacerier

7
@Pacerier ... เกี่ยวกับเวลาที่เหมาะสมในการแสดงความคิดเห็นแบบสุ่ม?
Dale

@Pierier ฉันไม่แน่ใจจริงๆว่าสิ่งที่คุณพยายามจะพูดด้วยความคิดเห็นนั้น "คือ .... " ... อะไรนะ! : P
scam

@Dale ตอนนี้เป็นเวลาที่เหมาะสม: ว้าวแม้ว่าคำถามจะซบเซาเป็นเวลา 2 ปีหลังจากที่คำว่า " ไร้สัญชาติ " ถูกเพิ่มลงใน GoogleDex ของอัตราการตีของ 3x-ed ในเวลาเพียง 6 เดือน
Pacerier

คำตอบ:


188

"ขอบเขตตัวแปร" คืออะไร?

ตัวแปรมี "ขอบเขต" ที่ จำกัด หรือ "สถานที่ที่สามารถเข้าถึงได้" เพียงเพราะคุณ$foo = 'bar';เคยเขียนที่ไหนสักแห่งในใบสมัครของคุณไม่ได้หมายความว่าคุณสามารถอ้างอิงได้$fooจากทุกที่ในแอปพลิเคชัน ตัวแปร$fooมีขอบเขตที่แน่นอนซึ่งถูกต้องและรหัสเฉพาะในขอบเขตเดียวกันเท่านั้นที่สามารถเข้าถึงตัวแปรได้

ขอบเขตที่กำหนดไว้ใน PHP เป็นอย่างไร

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

ตัวอย่าง:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$fooอยู่ในโลกขอบเขต$bazอยู่ในท้องถิ่นmyFuncที่อยู่ภายในขอบเขต รหัสภายในเท่านั้นที่myFuncสามารถเข้าถึง$bazได้ รหัสภายนอก เท่านั้นที่myFuncสามารถเข้าถึง$fooได้ ไม่มีสิทธิ์เข้าถึงอีก:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

ขอบเขตและไฟล์รวม

ขอบเขตไฟล์ไม่ได้แยกขอบเขต:

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

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

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

ในตัวอย่างข้างต้นa.phpรวมอยู่ภายในmyFuncตัวแปรใด ๆ ภายในa.phpเท่านั้นที่มีขอบเขตฟังก์ชั่นในท้องถิ่น เพียงเพราะพวกเขาดูเหมือนจะอยู่ในขอบเขตทั่วโลกในa.phpไม่จำเป็นต้องหมายความว่าพวกเขาเป็นจริงขึ้นอยู่กับบริบทที่รหัสรวม / ดำเนินการมา

ฟังก์ชั่นเกี่ยวกับฟังก์ชั่นภายในฟังก์ชั่นและชั้นเรียน?

functionการประกาศใหม่ทุกครั้งจะแนะนำขอบเขตใหม่นั่นง่ายมาก

ฟังก์ชั่น (ไม่ระบุชื่อ) ภายในฟังก์ชั่น

function foo() {
    $foo = 'bar';

    $bar = function () {
        // no access to $foo
        $baz = 'baz';
    };

    // no access to $baz
}

ชั้นเรียน

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

อะไรคือขอบเขตที่ดีสำหรับ?

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

สังเกต:

function foo() {
    echo $bar;
}

หากไม่มีขอบเขตฟังก์ชันข้างต้นจะทำอะไร ในกรณีที่ไม่$barมาจากไหน? รัฐนี้มีอะไร? มันจะเริ่มต้นได้ยัง? คุณต้องตรวจสอบทุกครั้งหรือไม่ สิ่งนี้ไม่สามารถบำรุงรักษาได้ ซึ่งนำเราไปที่ ...

ข้ามขอบเขตของขอบเขต

วิธีที่ถูกต้อง: ผ่านตัวแปรเข้าและออก

function foo($bar) {
    echo $bar;
    return 42;
}

ตัวแปร$barกำลังเข้ามาในขอบเขตนี้อย่างชัดเจนว่าเป็นอาร์กิวเมนต์ของฟังก์ชัน เพียงแค่ดูที่ฟังก์ชั่นนี้มันชัดเจนว่าค่าที่มันทำงานกับกำเนิด จากนั้นก็ชัดเจนส่งกลับค่า ผู้เรียกมีความมั่นใจในการรู้ว่าตัวแปรใดที่ฟังก์ชั่นนี้จะใช้งานและค่าที่ส่งคืนมาจาก:

$baz   = 'baz';
$blarg = foo($baz);

การขยายขอบเขตของตัวแปรไปสู่ฟังก์ชั่นนิรนาม

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

ฟังก์ชั่นที่ไม่ระบุชื่อรวมไว้อย่างชัดเจน$fooจากขอบเขตโดยรอบ โปรดทราบว่านี่ไม่ใช่ขอบเขตทั่วโลก

ทางที่ผิด: global

ดังที่กล่าวไว้ก่อนหน้านี้ขอบเขตทั่วโลกค่อนข้างพิเศษและฟังก์ชั่นสามารถนำเข้าตัวแปรจากมันได้อย่างชัดเจน:

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

ฟังก์ชั่นนี้ใช้และแก้ไขตัวแปร$fooกลาง อย่าทำอย่างนี้! (เว้นเสียแต่ว่าคุณจะรู้ว่ากำลังทำอะไรอยู่และจริงๆแล้ว: อย่า!)

ผู้เรียกฟังก์ชั่นนี้ทั้งหมดเห็นคือ:

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

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

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


คุณเพียงแค่กล่าวว่าวิธีที่ผิดglobalดังนั้นโปรดบอกเราเมื่อเราควรใช้global? และโปรดอธิบาย(เล็กน้อย)อะไรคือstatic.. ?

@stack ไม่มี "สิทธิ" globalสำหรับการเป็น มันผิดเสมอ พารามิเตอร์ฟังก์ชันการส่งผ่านนั้นถูกต้อง staticอธิบายได้ดีในคู่มือและไม่มีอะไรเกี่ยวข้องกับขอบเขต สรุปได้ว่ามันเป็น "ตัวแปรทั่วโลกที่กำหนดขอบเขต" ฉันขยายตัวเล็กน้อยกับการใช้งานของที่นี่kunststube.net/static
หลอกลวง

ความคิดง่ายๆของฉันคือถ้าตัวแปร php มีความสำคัญพอที่จะได้รับสถานะโกลบอลมันควรจะได้รับคอลัมน์ในฐานข้อมูล อาจจะเป็น overkill แต่เป็นวิธีการพิสูจน์คนโง่ที่เหมาะกับการเขียนโปรแกรมระดับปานกลางของฉันปัญญา
Arthur Tarasov

@Arthur มีมากที่จะแกะมี ... …_ಠนี่แน่นอนที่สุดไม่ใช่วิธีที่ฉันจะรับรอง
หลอกลวง

@deceze บิตของการโต้แย้งที่เกิดขึ้นที่นี่วันนี้ stackoverflow.com/q/51409392 - ที่ OP ระบุว่าการทำซ้ำ (ที่นี่) ไม่ได้กล่าวถึงinclude_onceและrequire_onceควรเพิ่มที่อื่น แค่พูด. OP โหวตให้เปิดคำถามอีกครั้ง โพสต์ของพวกเขาจะเป็นกรณีพิเศษและควรทำอย่างไรกับเรื่องนี้
Funk Forty Niner

10

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

'ตัวแปรคงที่' คืออะไร?

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

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

ผลลัพธ์:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

ถ้าเราต้องการที่กำหนด$counterโดยไม่ต้องstaticแล้วแต่ละครั้งค่าสะท้อนจะเป็นเช่นเดียวกับ$numพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชั่น การใช้staticอนุญาตให้สร้างตัวนับอย่างง่ายนี้โดยไม่มีวิธีแก้ไขเพิ่มเติม

ตัวแปรคงใช้กรณี

  1. เพื่อเก็บค่าระหว่างการเรียกใช้ฟังก์ชันที่ตามมา
  2. เพื่อจัดเก็บค่าระหว่างการโทรซ้ำเมื่อไม่มีทาง (หรือไม่มีจุดประสงค์) เพื่อส่งผ่านเป็น params
  3. เพื่อค่าแคชซึ่งโดยปกติดีกว่าที่จะดึงหนึ่งครั้ง ตัวอย่างเช่นผลลัพธ์ของการอ่านไฟล์ที่ไม่เปลี่ยนรูปบนเซิร์ฟเวอร์

เล่นกล

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

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

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

ผลลัพธ์:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

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

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

สิ่งนี้ใช้ได้กับวัตถุในคลาสเดียวกันเท่านั้น หากวัตถุมาจากคลาสที่แตกต่างกัน (แม้ขยายอีก) พฤติกรรมของ vars คงที่จะเป็นไปตามที่คาดไว้

ตัวแปรคงเป็นวิธีเดียวที่จะเก็บค่าระหว่างการเรียกไปยังฟังก์ชั่นหรือไม่?

อีกวิธีในการเก็บค่าระหว่างการเรียกใช้ฟังก์ชันคือการใช้การปิด การปิดตัวถูกนำมาใช้ใน PHP 5.3 คำสองคำนี้อนุญาตให้คุณ จำกัด การเข้าถึงตัวแปรบางชุดภายในขอบเขตฟังก์ชันไปยังฟังก์ชันที่ไม่ระบุชื่ออื่นซึ่งจะเป็นวิธีเดียวในการเข้าถึงตัวแปรเหล่านี้ การอยู่ในตัวแปรปิดอาจเลียนแบบ (มากหรือน้อยกว่าที่สำเร็จ) แนวคิดของ OOP เช่น 'ค่าคงที่คลาส' (หากค่าเหล่านั้นถูกส่งผ่านโดยการปิดตามค่า) หรือ 'คุณสมบัติส่วนตัว' (หากผ่านการอ้างอิง) ในการเขียนโปรแกรมแบบมีโครงสร้าง

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


2

ฉันจะไม่โพสต์คำตอบสำหรับคำถามอย่างสมบูรณ์เนื่องจากคำตอบที่มีอยู่เดิมและคู่มือ PHPทำหน้าที่อธิบายได้อย่างยอดเยี่ยม

แต่เรื่องหนึ่งที่พลาดเป็นที่ของsuperglobalsรวมทั้งที่ใช้กันทั่วไป$_POST, $_GET, $_SESSIONฯลฯ ตัวแปรเหล่านี้เป็นอาร์เรย์ที่มีอยู่เสมอในขอบเขตใด ๆ โดยไม่ต้องมีglobalการประกาศ

ตัวอย่างเช่นฟังก์ชั่นนี้จะพิมพ์ชื่อของผู้ใช้ที่เรียกใช้สคริปต์ PHP ตัวแปรพร้อมใช้งานสำหรับฟังก์ชั่นโดยไม่มีปัญหาใด ๆ

<?php
function test() {
    echo $_ENV["user"];
}

กฎทั่วไปของ "globals is bad" โดยทั่วไปแล้วจะถูกแก้ไขใน PHP เป็น "globals ไม่ดี แต่ superglobals นั้นใช้ได้" ตราบใดที่เราไม่ใช้มันในทางที่ผิด (ตัวแปรทั้งหมดเหล่านี้เขียนได้ดังนั้นพวกเขาสามารถใช้เพื่อหลีกเลี่ยงการฉีดขึ้นอยู่กับว่าคุณน่ากลัวจริง ๆ )

ไม่รับประกันว่าจะมีตัวแปรเหล่านี้ ผู้ดูแลระบบสามารถปิดการใช้งานบางส่วนหรือทั้งหมดโดยใช้variables_orderคำสั่งในphp.iniแต่นี่ไม่ใช่พฤติกรรมที่พบบ่อย


รายการของ superglobals ปัจจุบัน:

  • $GLOBALS - ตัวแปรโกลบอลทั้งหมดในสคริปต์ปัจจุบัน
  • $_SERVER - ข้อมูลเกี่ยวกับเซิร์ฟเวอร์และสภาพแวดล้อมการทำงาน
  • $_GET - ค่าที่ส่งผ่านในสตริงการสืบค้นของ URL โดยไม่คำนึงถึงวิธีการ HTTP ที่ใช้สำหรับการร้องขอ
  • $_POST- ค่าที่ส่งผ่านในคำขอ HTTP POST ด้วยapplication/x-www-form-urlencodedหรือmultipart/form-dataประเภท MIME
  • $_FILES - ไฟล์ถูกส่งผ่านในคำขอ HTTP POST พร้อมกับ multipart/form-dataประเภท MIME
  • $_COOKIE - คุกกี้ถูกส่งผ่านพร้อมกับคำขอปัจจุบัน
  • $_SESSION - ตัวแปรเซสชันถูกเก็บไว้ภายในโดย PHP
  • $_REQUEST- โดยปกติการรวมกันของ$_GETและแต่บางครั้ง$_POST $_COOKIESเนื้อหาจะถูกกำหนดโดยrequest_orderคำสั่งphp.iniใน
  • $_ENV - ตัวแปรสภาพแวดล้อมของสคริปต์ปัจจุบัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.