ตัวแปรทั่วโลกใน PHP ถือเป็นการปฏิบัติที่ไม่ดีหรือไม่? ถ้าเป็นเช่นนั้นทำไม?


86
function foo () {
    global $var;
    // rest of code
}

ในโครงการ PHP ขนาดเล็กของฉันฉันมักจะทำตามขั้นตอน ฉันมักจะมีตัวแปรที่มีการกำหนดค่าระบบและเมื่อฉัน Nead global $var;เข้าถึงตัวแปรนี้ในการทำงานที่ผมทำ

การปฏิบัติที่ไม่ดีนี้หรือไม่?


19
global variable เป็นคำพ้องความหมายสำหรับการปฏิบัติที่ไม่ดี
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳


2
ลองทดสอบหน่วย / การยอมรับแล้วคุณจะพบได้อย่างรวดเร็วว่าเหตุใด globals จึงเป็นปัญหา: ทำให้โค้ดของคุณไม่น่าเชื่อถือเมื่อคุณทำสิ่งต่างๆมากกว่าหนึ่งครั้ง
Kzqai

คำตอบ:


103

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

บ่อยครั้ง (เสมอ?) คุณสามารถเรียกใช้ฟังก์ชันสมาชิกด้วยวิธีpreg_replace_callback()การดังนี้:

preg_replace_callback('!pattern!', array($obj, 'method'), $str);

ดูการโทรกลับสำหรับข้อมูลเพิ่มเติม

ประเด็นคือวัตถุถูกยึดเข้ากับ PHP และในบางวิธีทำให้เกิดความอึดอัด

อย่ากังวลกับตัวเองมากเกินไปกับการนำมาตรฐานหรือโครงสร้างจากภาษาต่างๆไปใช้กับ PHP ข้อผิดพลาดที่พบบ่อยอีกประการหนึ่งคือการพยายามเปลี่ยน PHP ให้เป็นภาษา OOP ที่บริสุทธิ์โดยยึดโมเดลวัตถุไว้ด้านบนของทุกสิ่ง

เช่นเดียวกับสิ่งอื่น ๆ ให้ใช้ตัวแปร "global" รหัสขั้นตอนกรอบงานเฉพาะและ OOP เพราะมันสมเหตุสมผลแก้ปัญหาลดจำนวนรหัสที่คุณต้องเขียนหรือทำให้บำรุงรักษาได้มากขึ้นและเข้าใจง่ายขึ้นไม่ใช่เพราะคุณคิดว่า คุณควร.


8
ควรสังเกตว่า PHP 5.3 แก้ไขปัญหานี้ด้วยฟังก์ชันแลมบ์ดาซึ่งช่วยให้คุณหลีกเลี่ยงการใช้ฟังก์ชันที่ประกาศในขอบเขตทั่วโลกสำหรับการโทรกลับ +1 สำหรับคำแนะนำเกี่ยวกับรหัสที่บำรุงรักษาและอ่านได้
Jonathan Fingland

คุณไม่สามารถใช้การโทรกลับของแบบฟอร์มarray ($obj, 'callbackMethod')ในการโทรได้preg_replace_callback()หรือไม่ (ฉันรู้ฉันตกเป็นเหยื่อของข้อผิดพลาด OOP นี้ ... )
grossvogel

26
คำถามคือ "ไม่ควรใช้ตัวแปรส่วนกลางหรือไม่" คำตอบก็คือ 'ในบางโอกาสถ้าจำเป็น' คำถามคือพวกเขาปฏิบัติไม่ดี คำตอบคือ 'ใช่บางครั้ง' สำหรับโปรเจ็กต์ขนาดเล็กของโปสเตอร์อาจไม่มีอะไรเลวร้ายเกิดขึ้น - อย่างไรก็ตามสำหรับโปรเจ็กต์ขนาดใหญ่ที่มีสมาชิกในทีมจำนวนมากและชิ้นส่วนที่เคลื่อนไหวจำนวนมากการใช้ตัวแปรทั่วโลกอย่างหนักจะทำให้โค้ดนั้นยากต่อการดีบั๊กแทบจะเป็นไปไม่ได้ที่จะ refactor และสร้างความเจ็บปวดให้กับ อ่าน. ใช้เป็นบางครั้งได้ไหม, .. แน่ใจ - พวกเขาน่าดูด, .. เย้!
eddiemoya

@eddiemoya เอ็ดดี้พูดดี มีคนจำนวนมากอ้างเหตุผลการปฏิบัติที่ไม่ดีเช่นการใช้ตัวแปรทั่วโลก คุณควรหลีกเลี่ยงพวกมันเช่นโรคระบาด วุฒิการศึกษาด้านวิศวกรรมซอฟต์แวร์ที่ดีจะเจาะลึกลงไปในตัวคุณ ... อาจารย์ไม่เพียง แต่บอกคุณถึงนรกของมัน ... คุณควรใช้ฟังก์ชันสมาชิกเมื่อเป็นไปได้เพื่อเข้าถึงค่าที่คุณต้องการตัวอย่างเช่น get_query_var () ใน Wordpress เป็นต้น

27

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

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

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

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


แต่ข้อผิดพลาดส่วนใหญ่แสดงให้เห็นว่าไฟล์ / บรรทัดใดที่สคริปต์พังดังนั้น .. ฉันไม่เห็นปัญหาที่นี่
samayo

8
สถานที่ที่สคริปต์พัง! = สถานที่ที่ทำผิดพลาด
HonoredMule

16

ฉันเห็นด้วยกับ cletus ฉันจะเพิ่มสองสิ่ง:

  1. ใช้คำนำหน้าเพื่อให้คุณสามารถระบุได้ทันทีว่าเป็น global (เช่น $ g_)
  2. ประกาศพวกเขาในจุดเดียวอย่าไปโรยมันให้ทั่วรหัส

ขอแสดงความนับถือดอน


1
ใช่ฉันมักจะนำหน้าตัวแปรที่ฉันตั้งใจจะใช้ทั่วโลกด้วยเครื่องหมายขีดล่าง
KRTac

10
@KRTac แต่โดยปกติแล้ว $ _testVariable จะเป็นตัวแปรส่วนตัวซึ่งเป็นมาตรฐานที่ไม่เป็นทางการในการกำหนดตัวแปรส่วนตัวไม่ใช่ตัวแปรส่วนกลาง
Aditya MP

6
แนวทางปฏิบัติทั่วไปคือการกำหนดตัวแปรส่วนกลางโดยใช้ตัวพิมพ์ใหญ่ทั้งหมด ตัวอย่าง:$DB = 'foo';
pixeline

7

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

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

หากนั่นหมายถึงการใช้ตัวแปรสองสามตัว (<10) ในเนมสเปซส่วนกลางนั่นจะถูกใช้ในพื้นที่ส่วนกลางของโปรแกรมเท่านั้นดังนั้นไม่ว่าจะเป็น ใช่ใช่ MVC การฉีดพึ่งพารหัสภายนอก blah blah blah blah แต่ถ้าคุณมีโค้ด 99.99% ในเนมสเปซและคลาสและโค้ดภายนอกเป็นแซนด์บ็อกซ์โลกจะไม่สิ้นสุด (ขอย้ำโลกจะไม่จบ) หากคุณใช้ตัวแปรส่วนกลาง

โดยทั่วไปผมจะไม่บอกว่าใช้ตัวแปรทั่วโลกมีการปฏิบัติที่ไม่ดี ฉันจะบอกว่าการใช้ตัวแปรส่วนกลาง (แฟล็กและอื่น ๆ ) นอกพื้นที่ทั่วโลกของโปรแกรมกำลังขอปัญหาและ (ในระยะยาว) ไม่ได้รับคำแนะนำเพราะคุณสามารถสูญเสียการติดตามสถานะของพวกเขาได้ค่อนข้างง่าย นอกจากนี้ฉันจะบอกว่ายิ่งคุณเรียนรู้มากเท่าไหร่คุณก็จะยิ่งพึ่งพาตัวแปรระดับโลกน้อยลงเท่านั้นเพราะคุณจะได้สัมผัสกับ "ความสุข" ในการติดตามจุดบกพร่องที่เกี่ยวข้องกับการใช้งาน สิ่งนี้เพียงอย่างเดียวจะกระตุ้นให้คุณหาวิธีอื่นในการแก้ปัญหาเดียวกัน บังเอิญสิ่งนี้มีแนวโน้มที่จะผลักดันคน PHP ไปในทิศทางของการเรียนรู้วิธีใช้เนมสเปซและคลาส (สมาชิกแบบคงที่ ฯลฯ ... )

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

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


3

โพสต์ใหม่จาก SO Documentation Beta ที่สิ้นสุดแล้ว

เราสามารถอธิบายปัญหานี้ด้วยรหัสหลอกต่อไปนี้

function foo() {
     global $bob;
     $bob->doSomething();
}

คำถามแรกของคุณนี่เป็นคำถามที่ชัดเจน

ในกรณีที่ไม่$bobมาจากไหน?

คุณสับสนไหม? ดี. คุณเพิ่งได้เรียนรู้ว่าเหตุใดคนทั่วโลกจึงสับสนและถือเป็นการปฏิบัติที่ไม่ดี หากนี่เป็นโปรแกรมจริงความสนุกถัดไปของคุณคือการติดตามทุกกรณี$bobและหวังว่าคุณจะพบสิ่งที่ใช่ (จะแย่ลงถ้า$bobใช้ทุกที่) แย่กว่านั้นถ้ามีคนอื่นไปกำหนด$bob(หรือคุณลืมและใช้ตัวแปรนั้นซ้ำ) โค้ดของคุณอาจพังได้ (ในตัวอย่างโค้ดด้านบนการมีอ็อบเจ็กต์ที่ไม่ถูกต้องหรือไม่มีอ็อบเจ็กต์เลยจะทำให้เกิดข้อผิดพลาดร้ายแรง) เนื่องจากโปรแกรม PHP เกือบทั้งหมดใช้ประโยชน์จากรหัสเช่นinclude('file.php');งานของคุณที่ดูแลรหัสเช่นนี้จะยากขึ้นเรื่อย ๆ เมื่อคุณเพิ่มไฟล์มากขึ้น

เราจะหลีกเลี่ยง Globals ได้อย่างไร?

วิธีที่ดีที่สุดเพื่อหลีกเลี่ยงการ Globals คือปรัชญาที่เรียกว่าการพึ่งพาการฉีด นี่คือที่ที่เราส่งผ่านเครื่องมือที่เราต้องการไปยังฟังก์ชันหรือคลาส

function foo(\Bar $bob) {
    $bob->doSomething();
}

สิ่งนี้ง่ายกว่ามากในการทำความเข้าใจและดูแลรักษา ไม่มีการคาดเดาว่า$bobถูกตั้งค่าไว้ที่ใดเนื่องจากผู้โทรมีหน้าที่รับรู้สิ่งนั้น (กำลังส่งผ่านสิ่งที่เราต้องรู้) ยังดีกว่าเราสามารถใช้การประกาศประเภทเพื่อ จำกัด สิ่งที่กำลังส่งผ่าน ดังนั้นเราจึงรู้ว่านั่น$bobเป็นตัวอย่างของBarคลาสหรือตัวอย่างของเด็กBarซึ่งหมายความว่าเรารู้ว่าเราสามารถใช้วิธีการของคลาสนั้นได้ เมื่อรวมกับตัวโหลดอัตโนมัติมาตรฐาน (พร้อมใช้งานตั้งแต่ PHP 5.3) ตอนนี้เราสามารถติดตามตำแหน่งที่Barกำหนดไว้ได้ PHP 7.0 หรือใหม่กว่ามีการประกาศประเภทขยายซึ่งคุณสามารถใช้ประเภทสเกลาร์ (เช่นintหรือstring) ได้


อีกทางเลือกหนึ่งที่จะต้องส่ง $ bob ไปทุกหนทุกแห่งคือการทำให้คลาส Bar เป็นซิงเกิลตันการจัดเก็บอินสแตนซ์ของ Bar แบบคงที่ภายใน Bar เองและใช้วิธีการแบบคงที่เพื่อสร้างอินสแตนซ์ / ดึงวัตถุ จากนั้นคุณสามารถทำได้$bob = Bar::instance();ทุกเมื่อที่ต้องการ
Scoots

1
เพิ่งทราบว่า Singletons จะถือว่าเป็นรูปแบบการป้องกัน Dependency Injection หลีกเลี่ยงข้อผิดพลาดเหล่านั้น
Machavity

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

1

เช่น:

global $my_global; 
$my_global = 'Transport me between functions';
Equals $GLOBALS['my_global']

เป็นการปฏิบัติที่ไม่ดี (เช่น Wordpress $pagenow) ... อืม

พิจารณาสิ่งนี้:

$my-global = 'Transport me between functions';

เป็นข้อผิดพลาดของ PHPแต่:

$GLOBALS['my-global'] = 'Transport me between functions';

คือไม่ผิดพลาดhypens จะไม่ปะทะกับ "คนธรรมดา" $pagenowผู้ใช้ประกาศตัวแปรเช่น และการใช้ UPPERCASE บ่งบอกถึงการใช้งานระดับซูเปอร์โกลบอลจุดรหัสง่ายหรือติดตามด้วยการค้นหาในไฟล์

ฉันใช้ยัติภังค์ถ้าฉันขี้เกียจสร้างคลาสทุกอย่างสำหรับโซลูชันเดียวเช่น:

$GLOBALS['PREFIX-MY-GLOBAL'] = 'Transport me ... ';

แต่ในกรณีของการใช้งานที่กว้างขึ้นฉันใช้ONE globals เป็นอาร์เรย์:

$GLOBALS['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... ';
$GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... ';

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

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