PHP ทั่วโลกในฟังก์ชัน


100

ยูทิลิตี้ของคำหลักสากลคืออะไร?

มีเหตุผลใดบ้างที่จะชอบวิธีการหนึ่งมากกว่าวิธีอื่น

  • ความปลอดภัย?
  • ประสิทธิภาพ?
  • มีอะไรอีกไหม

วิธีที่ 1:

function exempleConcat($str1, $str2)
{
  return $str1.$str2;
}

วิธีที่ 2:

function exempleConcat()
{
  global $str1, $str2;
  return $str1.$str2;
}

เมื่อไม่ได้ทำให้ความรู้สึกที่จะใช้global?

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

ขอบคุณล่วงหน้า!


เงินรางวัล

นี่เป็นคำถามทั่วไปที่ดีเกี่ยวกับหัวข้อนี้ฉัน (@Gordon) กำลังเสนอเงินรางวัลเพื่อรับคำตอบเพิ่มเติม ไม่ว่าคำตอบของคุณจะเห็นด้วยกับของฉันหรือให้มุมมองที่แตกต่างออกไปก็ไม่สำคัญ เนื่องจากมีglobalหัวข้อปรากฏขึ้นเป็นระยะ ๆ เราจึงสามารถใช้คำตอบแบบ "บัญญัติ" ที่ดีเพื่อเชื่อมโยง


2
ดูได้ที่ลิงค์นี้: stackoverflow.com/questions/1557787 มีบทความที่เกี่ยวข้องมากมายที่ด้านล่างขวาของหน้านี้
JohnP

ไม่ใช่คำตอบโดยตรงสำหรับคำถามของคุณ แต่โปรดอ่านคำถาม SO ที่เก่ากว่านี้
Ólafur Waage

1
ดังนั้นฉันไม่สามารถอ่านคีย์เวิร์ดระดับโปรทั่วโลกได้ 1)ทำไมจึงมาที่นี่ 2)ทำไมคนใช้?
Pascal Qyy

@ G.Qyy มีไว้ทำไมgoto? ทำไมคนถึงใช้? พวกเขาไม่ใช้มัน (ฉันหวังว่าอย่างน้อย): P
PeeHaa

เมื่อปลายปีที่แล้ว (14 ธ.ค. ) มีคนโหวตคำถามนี้ไม่ลง ฉันสนใจมากที่จะรู้ว่าทำไมเพราะมุมมองทั้งหมดรวมถึงมุมมองเชิงลบนั้นน่าสนใจ ในกรณีนี้มากขึ้นกว่าเดิม! ฉันจะขอบคุณมากสำหรับเบาะแสเกี่ยวกับเรื่องนี้
Pascal Qyy

คำตอบ:


158

โกลบัลเป็นสิ่งชั่วร้าย

สิ่งนี้เป็นจริงสำหรับglobalคีย์เวิร์ดเช่นเดียวกับทุกสิ่งอื่น ๆ ที่มาถึงจากขอบเขตในพื้นที่ไปจนถึงขอบเขตส่วนกลาง (สถิตยศาสตร์, singletons, register, ค่าคงที่) คุณไม่ต้องการใช้มัน การเรียกใช้ฟังก์ชันไม่ควรต้องพึ่งพาสิ่งใดภายนอกเช่น

function fn()
{
    global $foo;              // never ever use that
    $a = SOME_CONSTANT        // do not use that
    $b = Foo::SOME_CONSTANT;  // do not use that unless self::
    $c = $GLOBALS['foo'];     // incl. any other superglobal ($_GET, …)
    $d = Foo::bar();          // any static call, incl. Singletons and Registries
}

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

ใช้ superglobals อาจจะไม่ได้ข้อบกพร่องที่เห็นได้ชัด แต่ถ้าคุณเรียกรหัสของคุณจากบรรทัดคำสั่งคุณไม่ได้หรือ$_GET $_POSTหากรหัสของคุณอาศัยข้อมูลจากสิ่งเหล่านี้แสดงว่าคุณกำลัง จำกัด ตัวเองให้อยู่ในสภาพแวดล้อมเว็บ เพียงแค่สรุปคำขอเป็นวัตถุและใช้สิ่งนั้นแทน

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

การใช้ซ้ำจะถูกขัดขวางอย่างรุนแรงจากทั้งหมดข้างต้น เพื่อให้เป็นหน่วยทดสอบ

นอกจากนี้ลายเซ็นฟังก์ชันของคุณยังโกหกเมื่อคุณจับคู่กับขอบเขตทั่วโลก

function fn()

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

หากฟังก์ชันของคุณต้องการอาร์กิวเมนต์ในการทำงานให้กำหนดให้ชัดเจนและส่งต่อใน:

function fn($arg1, $arg2)
{
    // do sth with $arguments
}

บ่งบอกอย่างชัดเจนจากลายเซ็นว่าต้องเรียกว่าอะไร ไม่ได้ขึ้นอยู่กับสภาพแวดล้อมที่จะอยู่ในสถานะเฉพาะ คุณไม่ต้องทำ

$arg1 = 'foo';
$arg2 = 'bar';
fn();

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

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

หากไม่มีตัวอย่างที่ดีกว่าให้พิจารณา

function fn()
{
    global $foo;
    echo $foo;     // side effect: echo'ing
    $foo = 'bar';  // side effect: changing
}

แล้วคุณก็ทำ

$foo = 'foo';
fn(); // prints foo
fn(); // prints bar <-- WTF!!

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

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

แหล่งข้อมูลเพิ่มเติม:


10
ทำไม PHP ถึงใช้สิ่งเหล่านี้? มียูทิลิตี้หรือไม่? ฉันมักจะประหลาดใจกับการใช้งาน PHP ที่เป็นอันตรายซึ่งผู้คนจำนวนมากใช้ทุกครั้ง ... เป็นการยากที่ฉันจะเชื่อว่าไม่มีเหตุผลที่สมเหตุสมผล!
Pascal Qyy

5
ฉันหวังว่าคุณจะทำให้Globals มีขนาดใหญ่ขึ้น
มิต

3
ว้าวในที่สุดก็มีคนอธิบายได้ดีว่าทำไมลูกโลกถึงชั่วร้าย ... ฉันได้ยินมาตลอดและฉันก็เห็นตัวอย่างที่เฉพาะเจาะจงมากว่าทำไม แต่นี่เป็นคำอธิบายที่ดีและครอบคลุมสำหรับเหตุผลทั่วไปว่าทำไม +1
Wingblade

ฉันมาสายจริงๆและฉันเข้าใจในสิ่งที่คุณพูด แต่การเชื่อมต่อ mysqli ล่ะ ควรส่งค่าเหล่านี้เป็นพารามิเตอร์ทุกครั้งหรือเป็น global $ link ได้รับอนุญาตในสายตาของคุณ?
Mave

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

35

เหตุผลใหญ่ประการหนึ่งglobalคือหมายความว่าฟังก์ชันขึ้นอยู่กับขอบเขตอื่น สิ่งนี้จะยุ่งเร็วมาก

$str1 = 'foo';
$str2 = 'bar';
$str3 = exampleConcat();

เทียบกับ

$str = exampleConcat('foo', 'bar');

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

globalเป็นรูปแบบที่ไม่ดีแม้จะรวมสิ่งต่างๆทั่วโลกเช่น$dbทรัพยากร จะมีวันที่คุณต้องการเปลี่ยนชื่อ$dbแต่ทำไม่ได้เพราะแอปพลิเคชันทั้งหมดของคุณขึ้นอยู่กับชื่อ

การ จำกัด และแยกขอบเขตของตัวแปรเป็นสิ่งสำคัญสำหรับการเขียนแอปพลิเคชันที่ซับซ้อนครึ่งทาง


1
ฉันขอโทษ แต่ทำไมฉันถึงอยากเปลี่ยนชื่อ$dbล่ะ มันคือกปปส. ผ่านไปทุกที่ เหตุใดจึงมีการเปลี่ยนแปลงเมื่อฉันสามารถอัปเดตข้อมูลการเชื่อมต่อแยกกัน
Casey Dwayne

3
@kcd เพราะวันหนึ่งคุณได้รู้ว่าการฉีดพึ่งพาดีแค่ไหนและต้องการปรับโครงสร้างแอปของคุณใหม่? เพราะวันหนึ่งคุณจะต้องบูรณาการข้อมูลของคุณกับบางสิ่งอื่น ๆ ที่ยังใช้ทั่วโลก$dbตัวแปร? เพราะวันหนึ่งคุณจะค้นพบการทดสอบหน่วยและจำเป็นต้องจัดการการเชื่อมต่อฐานข้อมูลมากกว่าหนึ่งครั้งเพื่อสิ่งนั้น? หลายหลายเหตุผล
หลอกลวง

35

Globals เป็นสิ่งที่หลีกเลี่ยงไม่ได้

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

ดูรหัสของ Zend - และโปรดเข้าใจว่าฉันไม่ได้แนะนำว่า Zend เขียนไม่ดี:

class DecoratorPluginManager extends AbstractPluginManager
{
/**
 * Default set of decorators
 *
 * @var array
 */
protected $invokableClasses = array(
    'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
    'htmltag'   => 'Zend\Tag\Cloud\Decorator\HtmlTag',
    'tag'       => 'Zend\Tag\Cloud\Decorator\HtmlTag',
   );

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

แอปพลิเคชันอื่นที่ใช้กันทั่วโลกคือ Drupal พวกเขากังวลมากเกี่ยวกับการออกแบบที่เหมาะสม แต่เช่นเดียวกับกรอบงานใหญ่ ๆ พวกเขามีการพึ่งพาภายนอกมากมาย ดูบอลโลกในหน้านี้:

/**
 * @file
 * Initiates a browser-based installation of Drupal.
 */

/**
 * Root directory of Drupal installation.
 */
define('DRUPAL_ROOT', getcwd());

/**
 * Global flag to indicate that site is in installation mode.
 */
define('MAINTENANCE_MODE', 'install');

// Exit early if running an incompatible PHP version to avoid fatal errors.
if (version_compare(PHP_VERSION, '5.2.4') < 0) {
  print 'Your PHP installation is too old. Drupal requires at least PHP 5.2.4. See the     <a     href="http://drupal.org/requirements">system requirements</a> page for more     information.';
  exit;
}

// Start the installer.
require_once DRUPAL_ROOT . '/includes/install.core.inc';
install_drupal();

เคยเขียนการเปลี่ยนเส้นทางไปยังหน้าเข้าสู่ระบบหรือไม่? นั่นคือการเปลี่ยนแปลงมูลค่าทั่วโลก (แล้วคุณไม่ได้พูดว่า 'WTF' ซึ่งฉันถือว่าเป็นปฏิกิริยาที่ดีต่อเอกสารที่ไม่ดีของแอปพลิเคชันของคุณ) ปัญหาเกี่ยวกับ globals ไม่ใช่ว่าพวกเขาเป็นลูกโลกคุณต้องใช้เพื่อให้มีแอปพลิเคชันที่มีความหมาย ปัญหาคือความซับซ้อนของแอปพลิเคชันโดยรวมซึ่งอาจทำให้เป็นฝันร้ายในการจัดการ เซสชันเป็นแบบโกลบอล $ _POST เป็นโกลบอล DRUPAL_ROOT เป็นโกลบอลรวม / install.core.inc 'เป็นโกลบอลที่ไม่สามารถแก้ไขได้ มีโลกใบใหญ่ภายนอกฟังก์ชันใด ๆ ที่จำเป็นเพื่อให้ฟังก์ชันนั้นทำงานได้

คำตอบของกอร์ดอนนั้นไม่ถูกต้องเพราะเขาใช้ความเป็นอิสระของฟังก์ชันมากเกินไปและการเรียกฟังก์ชันว่าคนโกหกทำให้สถานการณ์ง่ายขึ้น ฟังก์ชั่นไม่โกหกและเมื่อคุณดูตัวอย่างของเขาฟังก์ชั่นนั้นได้รับการออกแบบอย่างไม่เหมาะสมตัวอย่างของเขาคือบั๊ก (ฉันเห็นด้วยกับข้อสรุปนี้ว่าควรแยกรหัสออก) คำตอบของการหลอกลวงไม่ใช่คำจำกัดความที่เหมาะสมของสถานการณ์ ฟังก์ชันจะทำงานภายในขอบเขตที่กว้างขึ้นเสมอและตัวอย่างของเขาก็ง่ายเกินไป เราทุกคนจะเห็นด้วยกับเขาว่าฟังก์ชันนั้นไร้ประโยชน์โดยสิ้นเชิงเพราะส่งคืนค่าคงที่ ฟังก์ชั่นนั้นเป็นการออกแบบที่ไม่ดี แต่อย่างใด หากคุณต้องการแสดงให้เห็นว่าการปฏิบัตินั้นไม่ดีโปรดมาพร้อมกับตัวอย่างที่เกี่ยวข้อง การเปลี่ยนชื่อตัวแปรตลอดทั้งแอปพลิเคชันไม่ใช่เรื่องใหญ่หากมี IDE ที่ดี (หรือเครื่องมือ) คำถามเกี่ยวกับขอบเขตของตัวแปรไม่ใช่ความแตกต่างของขอบเขตกับฟังก์ชัน มีเวลาที่เหมาะสมสำหรับฟังก์ชันในการทำหน้าที่ในกระบวนการ (นั่นคือเหตุผลที่สร้างขึ้นตั้งแต่แรก) และในเวลาที่เหมาะสมนั้นอาจมีผลต่อการทำงานของแอปพลิเคชันโดยรวมดังนั้นการทำงานกับตัวแปรส่วนกลาง . คำตอบของ xzyfer คือคำสั่งที่ไม่มีการโต้แย้ง Globals มีอยู่ในแอปพลิเคชันเช่นเดียวกับหากคุณมีฟังก์ชันขั้นตอนหรือการออกแบบ OOP สองวิธีถัดไปในการเปลี่ยนแปลงมูลค่าของโลกมีลักษณะเหมือนกัน: ดังนั้นการทำงานกับตัวแปรทั่วโลก คำตอบของ xzyfer คือคำสั่งที่ไม่มีการโต้แย้ง Globals มีอยู่ในแอปพลิเคชันเช่นเดียวกับหากคุณมีฟังก์ชันขั้นตอนหรือการออกแบบ OOP สองวิธีถัดไปในการเปลี่ยนแปลงมูลค่าของโลกมีลักษณะเหมือนกัน: ดังนั้นการทำงานกับตัวแปรทั่วโลก คำตอบของ xzyfer คือคำสั่งที่ไม่มีการโต้แย้ง Globals มีอยู่ในแอปพลิเคชันเช่นเดียวกับหากคุณมีฟังก์ชันขั้นตอนหรือการออกแบบ OOP สองวิธีถัดไปในการเปลี่ยนแปลงมูลค่าของโลกมีลักษณะเหมือนกัน:

function xzy($var){
 global $z;
 $z = $var;
}

function setZ($var){
 $this->z = $var;
}

ในทั้งสองกรณีคือค่าของ $ z ที่เปลี่ยนแปลงภายในฟังก์ชันเฉพาะ ในการเขียนโปรแกรมทั้งสองวิธีคุณสามารถทำการเปลี่ยนแปลงเหล่านั้นในที่อื่น ๆ ในโค้ดได้ คุณสามารถพูดได้ว่าการใช้ global คุณสามารถเรียก $ z ได้ทุกที่และเปลี่ยนที่นั่น ใช่คุณสามารถ. แต่คุณจะ? และเมื่อทำในสถานที่ที่ไม่เหมาะสมแล้วจะไม่เรียกว่าจุดบกพร่องหรือไม่?

Bob Fanger แสดงความคิดเห็นเกี่ยวกับ xzyfer

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

เพื่อให้เข้าใจมากขึ้นว่าเมื่อใดที่เป็นปัญหาในการทำงานกับ globals และคำหลัก global และเมื่อใดที่ฉันจะไม่แนะนำประโยคถัดไปซึ่งมาจาก Wim de Bie เมื่อเขียนเกี่ยวกับบล็อก: 'Personal yes, private no' เมื่อฟังก์ชันกำลังเปลี่ยนค่าของตัวแปรส่วนกลางเพื่อประโยชน์ในการทำงานของตัวเองฉันจะเรียกการใช้ตัวแปรส่วนกลางและจุดบกพร่องนั้นเป็นการส่วนตัว แต่เมื่อมีการเปลี่ยนแปลงตัวแปร global สำหรับการประมวลผลที่เหมาะสมของแอปพลิเคชันโดยรวมเช่นการเปลี่ยนเส้นทางของผู้ใช้ไปยังหน้าเข้าสู่ระบบนั่นคือในความคิดของฉันอาจเป็นการออกแบบที่ดีไม่ใช่โดยความหมายที่ไม่ดีและไม่แน่นอน ต่อต้านรูปแบบ

ในการย้อนกลับไปที่คำตอบของ Gordon, Deceze และ xzyfer: พวกเขาทั้งหมดมี 'ใช่ส่วนตัว' (และข้อบกพร่อง) เป็นตัวอย่าง นั่นคือเหตุผลที่พวกเขาไม่เห็นด้วยกับการใช้โกลบัล ฉันก็จะทำเกินไป อย่างไรก็ตามพวกเขาไม่ได้มาพร้อมกับตัวอย่าง "ใช่ส่วนตัวไม่ส่วนตัว" เหมือนที่ฉันเคยทำในคำตอบนี้หลายครั้ง


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

@Arjen: หากคุณค้นหาคีย์เวิร์ด global ใน Drupal 7.14 คุณจะได้รับความนิยมนับร้อย เป็นปัญหาเก่าสำหรับผู้ตั้งค่าสาธารณะ: คุณไม่ได้ควบคุมสถานที่ที่จะเปลี่ยนเมื่อคุณเปิดเผยต่อสาธารณะ ไม่แนะนำให้ใช้เลยหรือประกาศว่าเป็นส่วนตัวดังนั้นจึงไม่สามารถเพิ่มได้ในภายหลัง
Loek Bergman

@Arjan: เนื่องจากข้อผิดพลาดของฉันเกี่ยวกับการสะกดชื่อของคุณคุณไม่ได้รับการแจ้งเตือนใด ๆ เกี่ยวกับการตอบกลับของฉันที่มีต่อคุณ ตอนนี้คุณจะ :-)
Loek Bergman

@LoekBergman: มีเพลงฮิตประมาณ 400 คำสำหรับคำglobalใน drupal 7.26 (ซึ่งเป็นเวอร์ชันล่าสุด) บางส่วนของเพลงเหล่านั้นอยู่ในความคิดเห็นและอีกหลายรายการดูเหมือนจะอยู่ในรหัสที่ไม่ได้สัมผัสมานานหลายปี ฉันหวังว่าพวกเขาจะไม่ใช้globals ใน drupal 8
Arjan

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

15

พูดง่ายๆว่าไม่ค่อยมีเหตุผลglobalและไม่เคยเป็นสิ่งที่ดีในโค้ด PHP สมัยใหม่ IMHO โดยเฉพาะอย่างยิ่งถ้าคุณใช้ PHP 5 และพิเศษเป็นพิเศษหากคุณพัฒนา Object Orientated code

Globals ส่งผลเสียต่อการบำรุงรักษาความสามารถในการอ่านและการทดสอบโค้ด การใช้globalcan และควรแทนที่ด้วย Dependency Injection หรือเพียงแค่ส่ง global object เป็นพารามิเตอร์

function getCustomer($db, $id) {
    $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
    return $row;
}

10

อย่าลังเลที่จะใช้คำสำคัญทั่วโลกภายในฟังก์ชันใน PHP โดยเฉพาะอย่างยิ่งอย่าใช้คนที่เทศนา / ตะโกนว่าคนทั่วโลกว่า 'ชั่วร้าย' และอะไร

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

กรณีในประเด็น:

Wordpress และระบบนิเวศใช้คำหลักสากลในการทำงาน เป็นรหัส OOP หรือไม่ OOP

และ ณ ตอนนี้ Wordpress มีอินเทอร์เน็ตโดยทั่วไปถึง 18.9% และใช้งาน megasites / แอพขนาดใหญ่ของยักษ์ใหญ่มากมายนับไม่ถ้วนตั้งแต่ Reuters ไปจนถึง Sony ไปจนถึง NYT ไปจนถึง CNN

และมันก็ทำได้ดี

การใช้คำสำคัญทั่วโลกภายในฟังก์ชันช่วยให้ Wordpress เป็นอิสระจากการขยายขนาดใหญ่ซึ่งจะเกิดขึ้นเนื่องจากระบบนิเวศขนาดใหญ่ ลองนึกภาพว่าทุกฟังก์ชั่นถาม / ส่งผ่านตัวแปรใด ๆ ที่จำเป็นจากปลั๊กอินอื่นคอร์และส่งคืน เพิ่มด้วยการพึ่งพาระหว่างกันของปลั๊กอินซึ่งจะจบลงด้วยฝันร้ายของตัวแปรหรือฝันร้ายของอาร์เรย์ที่ส่งผ่านเป็นตัวแปร นรกในการติดตามนรกแห่งการดีบั๊กนรกที่ต้องพัฒนา รอยเท้าหน่วยความจำขนาดใหญ่โดยไม่ได้ตั้งใจเนื่องจากการขยายตัวของโค้ดและการขยายตัวของตัวแปรด้วย เขียนยากขึ้นด้วย

อาจมีคนมาวิพากษ์วิจารณ์ Wordpress ระบบนิเวศการปฏิบัติของพวกเขาและสิ่งที่เกิดขึ้นในส่วนเหล่านั้น

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

อีกตัวอย่างหนึ่งที่ดีคือ "iframes are evil" fundamentalism ทศวรรษที่แล้วการใช้ iframe เป็นเรื่องนอกรีต และมีคนหลายพันคนเทศนาต่อต้านพวกเขาในอินเทอร์เน็ต จากนั้น Facebook ก็มาถึงโซเชียลตอนนี้ iframe มีอยู่ทั่วไปตั้งแต่กล่อง 'like' ไปจนถึงการรับรองความถูกต้องและ voila - ทุกคนหุบปาก มีหลายคนที่ยังไม่หุบปาก - ถูกหรือผิด แต่คุณรู้ไหมว่าชีวิตดำเนินต่อไปแม้จะมีความคิดเห็นเช่นนี้และแม้แต่คนที่ประกาศต่อต้าน iframe เมื่อสิบปีก่อนก็ต้องใช้พวกเขาเพื่อรวมแอปโซเชียลต่างๆเข้ากับแอปพลิเคชันขององค์กรโดยไม่ต้องพูดอะไรเลย

......

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

อย่างไรก็ตามสำหรับคนส่วนใหญ่โลกนี้เป็นโลกที่เปลี่ยนแปลงตลอดเวลาซึ่งพวกเขาต้องเปิดใจกว้างและปฏิบัติได้จริง ไม่มีสถานที่สำหรับลัทธิพื้นฐานนิยมละทิ้งคำหลักที่ชั่วร้ายเช่น 'ชั่วร้าย' ไว้ในร่องลึกแนวหน้าของเทคโนโลยีสารสนเทศ

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

พวกเขาจะไม่ทำงานของคุณ คุณจะ. ปฏิบัติตามสถานการณ์ของคุณ


3
+1 สำหรับ anti-fundamentalism เป็นต้น แต่การพูดว่า "ผู้คนจำนวนมากใช้มัน / มันได้ผล / ฯลฯ " เป็นเพียง "อาร์กิวเมนต์โฆษณาป๊อปลัม" ซึ่งเป็นความซับซ้อนขั้นพื้นฐาน การที่คนส่วนใหญ่คิดหรือทำสิ่งหนึ่งไม่ได้พิสูจน์ว่าถูกต้อง! ในฝูงชนหากมีอันตรายปรากฏขึ้นผู้คนส่วนใหญ่จะทำสิ่งที่โง่เขลาและบางคนจะถูกคนอื่นกระทืบตาย พวกเขาถูกต้องหรือไม่ที่จะเอาเท้าแตะใบหน้าของเด็กหญิงตัวเล็ก ๆ อายุห้าขวบคนนี้เพียงเพราะพวกเขาคิดว่าพวกเขาจะต้องผลักประตูที่เปิดออกถ้าถูกดึงเพื่อหนีไฟ? ฉันไม่คิดอย่างนั้น…
Pascal Qyy

1
ส่วนใหญ่ทำอะไรบางอย่างแน่นอนไม่ได้ตรวจสอบอะไรด้วยตัวเอง อย่างไรก็ตามกรณีนี้เป็นซอฟต์แวร์ และหากคนส่วนใหญ่ทำเช่นนั้นและแอปและบริการส่วนใหญ่ที่สร้างโดยคนเหล่านี้ถือเป็นประโยชน์อย่างดี (wordpress สำหรับคนอื่น ๆ ) ก็หมายความว่าสามารถใช้งานได้
unity100

7

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

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

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

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

  2. การใช้งาน globals อื่นมีไว้เพื่อวัตถุประสงค์ในการกำหนดค่า ส่วนใหญ่จะอยู่ที่จุดเริ่มต้นของสคริปต์ก่อนที่จะโหลดตัวโหลดอัตโนมัติการเชื่อมต่อฐานข้อมูลเป็นต้น

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

  3. การใช้งานขั้นสุดท้ายสำหรับ globals คือการเก็บข้อมูลทั่วไป (เช่น CRLF, IMAGE_DIR, IMAGE_DIR_URL) แฟล็กสถานะที่มนุษย์อ่านได้ (เช่น ITERATOR_IS_RECURSIVE) ที่นี่ globals ใช้เพื่อจัดเก็บข้อมูลที่ตั้งใจจะใช้กับแอพพลิเคชั่นที่อนุญาตให้เปลี่ยนแปลงได้และทำให้การเปลี่ยนแปลงเหล่านั้นปรากฏขึ้นทั่วทั้งแอปพลิเคชัน

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

    การใช้งาน php แบบใหม่ของอ็อบเจกต์จาก PHP 5.4+ ดูแลปัญหาเหล่านี้ส่วนใหญ่คุณสามารถส่งผ่านวัตถุไปรอบ ๆ ได้อย่างปลอดภัยโดยไม่ต้องรับโทษอีกต่อไป สิ่งนี้ไม่จำเป็นอีกต่อไป

    การใช้ singletons อีกอย่างคืออินสแตนซ์พิเศษที่ต้องมีอินสแตนซ์ของอ็อบเจ็กต์เพียงครั้งเดียวอินสแตนซ์นั้นอาจมีอยู่ก่อน / หลังการเรียกใช้สคริปต์และอ็อบเจ็กต์นั้นถูกแบ่งใช้ระหว่างสคริปต์ / เซิร์ฟเวอร์ / ภาษาที่แตกต่างกันเป็นต้นที่นี่รูปแบบซิงเกิลตันจะแก้ปัญหา วิธีแก้ปัญหาค่อนข้างดี

ดังนั้นโดยสรุปถ้าคุณอยู่ในตำแหน่ง 1, 2 หรือ 3 การใช้ global ก็สมเหตุสมผล อย่างไรก็ตามในสถานการณ์อื่น ๆ ควรใช้วิธีที่ 1

อย่าลังเลที่จะอัปเดตอินสแตนซ์อื่น ๆ ที่ควรใช้ globals


6

ไม่มีเหตุผลที่จะสร้างฟังก์ชัน concat โดยใช้คีย์เวิร์ดส่วนกลาง

ใช้เพื่อเข้าถึงตัวแปรส่วนกลางเช่นวัตถุฐานข้อมูล

ตัวอย่าง:

function getCustomer($id) {
  global $db;
  $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
  return $row;
}

สามารถใช้เป็นรูปแบบของรูปแบบ Singleton


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