ทำไม require_once แย่มากที่จะใช้


143

ทุกอย่างที่ฉันอ่านเกี่ยวกับการเขียนโค้ด PHP ที่ดีขึ้นนั้นบอกว่าอย่าใช้require_onceเพราะความเร็ว

ทำไมนี้

วิธีที่เหมาะสม / ดีกว่าที่จะทำสิ่งเดียวกันrequire_onceคืออะไร? หากเป็นเรื่องสำคัญฉันกำลังใช้ PHP 5


9
คำถามนี้ค่อนข้างเก่าแล้วและคำตอบนั้นเกี่ยวข้องกันอย่างน่าสงสัยอีกต่อไป มันจะดีที่จะเห็นการปรับปรุงของชุดคำตอบจากผู้เข้าร่วม :)
Purefan

คำตอบ:


108

require_onceและinclude_onceทั้งคู่ต้องการให้ระบบเก็บบันทึกสิ่งที่มีอยู่แล้ว / จำเป็น การ*_onceโทรทุกครั้งหมายถึงการตรวจสอบบันทึกนั้น ดังนั้นมีงานพิเศษบางอย่างที่ทำที่นั่น แต่พอที่จะทำให้ความเร็วของแอพลดลง?

... ผมสงสัยมัน ... ไม่เว้นแต่คุณจะอยู่บนจริงๆฮาร์ดแวร์เก่าหรือทำมันมาก

หากคุณกำลังทำหลายพัน*_onceคุณสามารถทำงานด้วยตัวเองในแบบเบา สำหรับแอปง่าย ๆ เพียงตรวจสอบให้แน่ใจว่าคุณได้รวมมันเพียงครั้งเดียวก็เพียงพอแล้ว แต่ถ้าคุณยังคงได้รับข้อผิดพลาดการกำหนดใหม่คุณสามารถทำสิ่งนี้:

if (!defined('MyIncludeName')) {
    require('MyIncludeName');
    define('MyIncludeName', 1);
}

ฉันจะยึดติดกับ*_onceแถลงการณ์เป็นการส่วนตัว แต่ด้วยเกณฑ์มาตรฐานล้านล้านโง่คุณสามารถเห็นความแตกต่างระหว่างสอง:

                php                  hhvm
if defined      0.18587779998779     0.046600103378296
require_once    1.2219581604004      3.2908599376678

10-100 ×ช้าลงด้วยrequire_onceและก็อยากรู้อยากเห็นที่ดูเหมือนจะช้าลงในrequire_once hhvmสิ่งนี้เกี่ยวข้องกับรหัสของคุณเฉพาะเมื่อคุณใช้งาน*_onceหลายพันครั้งเท่านั้น


<?php // test.php

$LIMIT = 1000000;

$start = microtime(true);

for ($i=0; $i<$LIMIT; $i++)
    if (!defined('include.php')) {
        require('include.php');
        define('include.php', 1);
    }

$mid = microtime(true);

for ($i=0; $i<$LIMIT; $i++)
    require_once('include.php');

$end = microtime(true);

printf("if defined\t%s\nrequire_once\t%s\n", $mid-$start, $end-$mid);

<?php // include.php

// do nothing.

29
ฉันสงสัยว่าเมธอด define () ของคุณเร็วกว่าตารางการค้นหาในตัว แต่ฉันเห็นด้วยกับประเด็นโดยรวมของคุณ - แน่นอนว่าไม่ใช่ปัญหา?!
บ๊อบบี้แจ็ค

1
ฉันค่อนข้างแน่ใจว่าคุณพูดถูกบ๊อบบี้ แต่ฉันไม่ได้สนับสนุนคำจำกัดความของ _once มันเป็นเพียงตัวเลือก เวลาที่ใช้ในการแปลรหัสอาจทำให้ช้าลงเล็กน้อย แต่ที่กล่าวว่าฉันไม่ทราบวิธีการภายในอย่างละเอียด มันอาจทำงานพิเศษเพื่อให้แน่ใจว่าไม่มีการทำซ้ำ
Oli

8
ข้อเสียอีกอย่างคือ APC ไม่ได้แคช include_once และ require_once เรียก IIRC
dcousineau

3
ฉันเพิ่งทดสอบพื้นฐานสองวิธี - ฉันทำซ้ำ 1,000,000 ครั้งรวมถึงไฟล์ที่กำหนด 'testinclude' ที่คงที่เป็นจริง ในการทดสอบครั้งแรกฉันใช้ require_once ครั้งที่สองที่ฉันใช้ถ้า (! define ('testinclude')) และผลลัพธ์น่าสนใจ: ต้องการ: 0.81639003753662 ไม่ได้กำหนด: 0.17906713485718 กำหนดได้เร็วขึ้น 0.63732290267944 microseconds
Travis Weston

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

150

กระทู้นี้ทำให้ฉันประจบประแจงเพราะมี "การแก้ปัญหาโพสต์" แล้วและสำหรับทุกเจตนาและวัตถุประสงค์ผิด ลองแจกแจง:

  1. กำหนดมีราคาแพงมากใน PHP คุณสามารถค้นหาหรือทดสอบด้วยตัวเอง แต่วิธีเดียวที่มีประสิทธิภาพในการกำหนดค่าคงที่ทั่วโลกใน PHP คือผ่านส่วนขยาย (ค่าคงที่คลาสเป็นค่าประสิทธิภาพที่ดีพอสมควร แต่นี่คือจุดที่สงสัยเนื่องจาก 2)

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

ดังนั้นในขณะที่คนจำนวนมากใช้class_exists()วิธีการรวมของพวกเขา ฉันไม่ชอบเพราะมันน่าเกลียด แต่พวกเขามีเหตุผลที่ดีที่: require_once()ค่อนข้างไม่มีประสิทธิภาพก่อนที่จะมี PHP เวอร์ชันล่าสุด แต่ที่ได้รับการแก้ไขและเป็นความขัดแย้งของฉันที่ bytecode พิเศษที่คุณต้องรวบรวมสำหรับเงื่อนไขและเรียกวิธีการพิเศษจะไกลเกินกว่าการตรวจสอบ hashtable ภายในใด ๆ

ตอนนี้การรับสมัคร: สิ่งนี้ยากที่จะทดสอบเพราะบัญชีมีเวลาดำเนินการเพียงเล็กน้อย

นี่คือคำถามที่คุณควรคำนึงถึง: การรวมเป็นกฎทั่วไปมีราคาแพงใน PHP เพราะทุกครั้งที่ล่ามกระทบจะต้องสลับกลับเข้าสู่โหมดแยกวิเคราะห์สร้าง opcodes แล้วกระโดดกลับ หากคุณมีการรวม 100+ สิ่งนี้จะส่งผลกระทบต่อประสิทธิภาพอย่างแน่นอน เหตุผลที่ใช้หรือไม่ใช้ require_once นั้นเป็นคำถามที่สำคัญมากเพราะมันทำให้ชีวิตยากขึ้นสำหรับแคช opcode คำอธิบายนี้สามารถพบได้ที่นี่ แต่สิ่งนี้เดือดลงไปคือ:

  • หากในช่วงเวลาการแยกวิเคราะห์คุณรู้ว่าสิ่งที่มีไฟล์รวมที่คุณจะต้องตลอดชีวิตของการร้องขอไฟล์require()ที่จุดเริ่มต้นมากและแคช opcode จะจัดการทุกอย่างอื่นสำหรับคุณ

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

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

  • ถ้าคุณมีอาจจะ 10 รวม (นี้เป็นอย่างมากหลังของการคำนวณซอง) ทั้งหมด wanking นี้จะไม่คุ้มค่า: เพียงแค่เพิ่มประสิทธิภาพการค้นหาฐานข้อมูลหรือบางสิ่งบางอย่างของคุณ


14
นี่คือ 4 ปีและส่วนใหญ่ไม่ได้มีผลบังคับใช้define(), require_once()และdefined()ใช้เวลาทั้งหมดประมาณ 1-2 microseconds แต่ละเครื่องของฉัน
Daniel Beardsley

72
แต่นั่นคือ 2 microseconds เร็ว ๆ นี้ผู้ใช้จะมีหน้า การดูหน้าเว็บเป็นเวลาหนึ่งปีซึ่งสามารถประหยัดผู้ใช้ได้ทั้ง 3 วินาที! พวกเขาสามารถดูโฆษณาหนึ่งในสิบในเวลานั้นได้! คิดถึงผู้ใช้ อย่าเสียไมโครวินาที
Andrew Ensley

15
เพียงเพื่อให้ทุกคนรับรู้ถึงการประชดประชันไมโครวินาทีเป็น 1/1000000 วินาที
Andy Chase

1
@AndrewEnsley คุณเข้าใจผิดว่าเป็นเรื่องถากถางของคุณทั้งหมด คุณไม่รู้เกี่ยวกับความจริงที่ว่า PHP ยังทำงานบนไมโครโปรเซสเซอร์, 1 ไมโครวินาทีบนพีซีของคุณคือมิลลิวินาทีหลายไมโครโปรเซสเซอร์ ทีนี้ถ้ามี 20 ไฟล์รวมแล้วเป็นโครงการที่ใหญ่กว่าเหรอ? นั่นคือ 20 เท่าของความล่าช้าที่แนะนำหลายมิลลิวินาทีดังนั้นเราจึงไปถึงจุดที่มนุษย์สามารถสังเกตได้ หากสคริปต์นั้นถูกเรียกบ่อยๆจะทำให้เกิดปัญหาประสิทธิภาพการทำงานในระบบ การเพิ่มประสิทธิภาพไม่ใช่เรื่องตลกและโลกทั้งใบไม่ได้หันมาใช้พีซีของคุณ มีซีพียูที่ใช้อยู่หมื่นตัว
จอห์น

2
@จอห์น. มันเป็นเรื่องตลกที่ทำในวิญญาณที่ดี ไม่มีเจตนาร้าย หากมันคุ้มค่าสำหรับคุณที่จะเพิ่มประสิทธิภาพการรวมของคุณไปข้างหน้า
Andrew Ensley

66

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

ฉันเริ่มต้นด้วยการสร้างไฟล์ส่วนหัว 100 ไฟล์ที่ใช้ require_once เพื่อรวมไฟล์ส่วนหัวอื่น แต่ละไฟล์เหล่านี้มีลักษณะดังนี้:

<?php
    // /home/fbarnes/phpperf/hdr0.php
    require_once "../phpperf/common_hdr.php";

?>

ฉันสร้างสิ่งเหล่านี้โดยใช้แฮ็ค Bash อย่างรวดเร็ว:

for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
    echo "<?php
    // $i" > $i
    cat helper.php >> $i;
done

วิธีนี้ฉันสามารถสลับระหว่างการใช้ require_once ได้อย่างง่ายดายและต้องการเมื่อรวมไฟล์ส่วนหัว ฉันสร้าง app.php ขึ้นมาเพื่อโหลดไฟล์หนึ่งร้อยไฟล์ ดูเหมือนว่า:

<?php
    // Load all of the php hdrs that were created previously
    for($i=0; $i < 100; $i++)
    {
        require_once "/home/fbarnes/phpperf/hdr$i.php";
    }

    // Read the /proc file system to get some simple stats
    $pid = getmypid();
    $fp = fopen("/proc/$pid/stat", "r");
    $line = fread($fp, 2048);
    $array = split(" ", $line);

    // Write out the statistics; on RedHat 4.5 with kernel 2.6.9
    // 14 is user jiffies; 15 is system jiffies
    $cntr = 0;
    foreach($array as $elem)
    {
        $cntr++;
        echo "stat[$cntr]: $elem\n";
    }
    fclose($fp);
?>

ฉันเปรียบเทียบส่วนหัว require_once กับส่วนหัวต้องใช้ซึ่งใช้ไฟล์ส่วนหัวที่มีลักษณะดังนี้:

<?php
    // /home/fbarnes/phpperf/h/hdr0.php
    if(!defined('CommonHdr'))
    {
        require "../phpperf/common_hdr.php";
        define('CommonHdr', 1);
    }
?>

ฉันไม่พบความแตกต่างมากนักเมื่อใช้งานโหมดนี้พร้อมกับ require และ require_once ในความเป็นจริงการทดสอบครั้งแรกของฉันดูเหมือนจะบอกเป็นนัยว่า require_once นั้นเร็วขึ้นเล็กน้อย แต่ฉันก็ไม่จำเป็นต้องเชื่อเช่นนั้น ฉันทำการทดสอบซ้ำกับไฟล์อินพุต 10,000 ไฟล์ ที่นี่ฉันเห็นความแตกต่างที่สอดคล้องกัน ฉันรันการทดสอบหลายครั้งผลลัพธ์ใกล้เคียงกัน แต่การใช้ require_once ใช้โดยเฉลี่ย 30.8 ผู้ใช้ jiffies และ 72.6 ระบบ jiffies การใช้ต้องการการใช้งานโดยเฉลี่ย 39.4 ผู้ใช้ jiffies และ 72.0 ระบบ jiffies ดังนั้นจึงปรากฏว่าโหลดน้อยลงเล็กน้อยโดยใช้ require_once อย่างไรก็ตามเวลานาฬิกาแขวนจะเพิ่มขึ้นเล็กน้อย การโทร 10,000 require_once ใช้เวลา 10.15 วินาทีในการดำเนินการโดยเฉลี่ยและ 10,000 การโทรต้องใช้ 9.84 วินาทีโดยเฉลี่ย

ขั้นตอนต่อไปคือการค้นหาความแตกต่างเหล่านี้ ฉันใช้straceเพื่อวิเคราะห์การเรียกระบบที่กำลังทำอยู่

ก่อนที่จะเปิดไฟล์จาก require_once การเรียกระบบต่อไปนี้จะทำ:

time(NULL)                              = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL)                              = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

สิ่งนี้ขัดแย้งกับความต้องการ:

time(NULL)                              = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL)                              = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

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

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
  190709 strace_1000r.out
  210707 strace_1000ro.out
  401416 total

อย่างมีประสิทธิภาพมีการเรียกใช้ระบบเพิ่มเติมอีกประมาณสองครั้งต่อไฟล์ส่วนหัวเมื่อใช้ require_once ข้อแตกต่างอย่างหนึ่งคือ require_once มีการเรียกใช้ฟังก์ชัน time () เพิ่มเติม:

[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20009
strace_1000ro.out:30008

การเรียกระบบอื่น ๆ คือ getcwd ():

[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out
strace_1000r.out:5
strace_1000ro.out:10004

สิ่งนี้ถูกเรียกเนื่องจากฉันตัดสินใจที่จะอ้างอิงพา ธ แบบอ้างอิงในไฟล์ hdrXXX ถ้าฉันทำสิ่งนี้เป็นการอ้างอิงที่แน่นอนความแตกต่างเพียงอย่างเดียวคือการเรียกเวลาเพิ่มเติม (NULL) ที่ทำในรหัส:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
  190705 strace_1000r.out
  200705 strace_1000ro.out
  391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008

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

อีกสิ่งหนึ่งที่ทราบคือแพ็คเกจการปรับให้เหมาะสมของ APC มีตัวเลือกที่เรียกว่า "apc.include_once_override" ซึ่งอ้างว่าจะลดจำนวนการเรียกใช้ระบบโดยการเรียกใช้ require_once และ include_once (ดูเอกสารประกอบ PHP )


6
และ "การเพิ่มประสิทธิภาพ" ใด ๆ ที่คุณต้องใช้ 10,000 ครั้งเพื่อดูความแตกต่างจิ๋วนั้นไม่คุ้มค่าที่จะกังวล ใช้ตัวสร้างโปรไฟล์และค้นหาว่าคอขวดที่แท้จริงอยู่ในใบสมัครของคุณ ฉันสงสัยคำถามนี้คือคอขวด
DGM

1
สิ่งนี้หมายความว่ามันไม่สำคัญเลย ใช้สิ่งที่ได้ผลดีกว่าสำหรับคุณอย่างมีเหตุผล
Buttle Butkus


21

คุณสามารถให้ลิงค์เชื่อมโยงกับการเข้ารหัสเหล่านี้เพื่อบอกให้เราหลีกเลี่ยงได้หรือไม่ เท่าที่ฉันเป็นห่วงมันไม่ใช่เรื่องสมบูรณ์ ฉันไม่ได้ดูซอร์สโค้ดด้วยตัวเอง แต่ฉันคิดว่าข้อแตกต่างระหว่างincludeและinclude_onceคือinclude_onceเพิ่มชื่อไฟล์นั้นให้กับอาเรย์และตรวจสอบอาเรย์ทุกครั้ง มันจะง่ายต่อการจัดเรียงอาร์เรย์นั้นดังนั้นการค้นหาควรเป็น O (log n) และแม้แต่แอปพลิเคชันขนาดกลางที่มีค่ามากจะมีเพียงไม่กี่โหลเท่านั้น


หนึ่งคือchazzuka.com/blog/?p=163พวกเขาไม่ได้ 'ไม่ไป' แต่รวมถึงสิ่งที่ 'แพง' มากเกินไป และที่จริงแล้วไฟล์ที่รวมอยู่ / ที่จำเป็นทั้งหมดจะถูกเพิ่มไปยังอาร์เรย์ภายใน (มีฟังก์ชั่นเพื่อส่งคืน) ฉันเดาว่า _once ต้องวนลูปอาร์เรย์นั้นและทำ strcmp ซึ่งจะเพิ่มขึ้น
Uberfuzzy

7

วิธีที่ดีกว่าที่จะทำสิ่งคือการใช้วิธีการเชิงวัตถุและการใช้__autoload ()


3
แต่ตัวอย่างแรกสุดในหน้าวัตถุการโหลดอัตโนมัติที่คุณเชื่อมโยงกับการใช้ require_once
Shabbyrobe

ฉันไม่ซื้อสิ่งนี้ มีหลายสถานการณ์ที่ OO ไม่เหมาะสมเท่ากระบวนทัศน์อื่น ๆ ดังนั้นคุณไม่ควรบังคับให้ได้รับผลประโยชน์เล็ก ๆ น้อย ๆ ที่อาจมีกับ __autoload ()
บ๊อบบี้แจ็ค

1
คุณคิดว่าการโหลดอัตโนมัติจะใช้เวลานานกว่า * _once (สมมติว่าคุณต้องการเพียงสิ่งที่คุณต้องการเท่านั้น)
nickf

ไม่มันไม่ได้อย่างน้อยไม่แน่นอน Autoload ยังคงต้องการที่จะรวมอย่างใดและมันก็เป็นทางเลือกสุดท้ายสำหรับ PHP ก่อนที่จะเกิดข้อผิดพลาดล้มเหลว - ดังนั้นในความเป็นจริง PHP จริงดำเนินการตรวจสอบที่ไม่จำเป็น potentionally ผ่านสถานที่ทั้งหมดที่จะนำไปใช้รวม / ต้องการและหลัง ว่ามันจะเรียกว่า autoload (ถ้ามีการกำหนดไว้) ... PS: __autoload()หมดกำลังใจและอาจเลิกใช้ในอนาคตคุณควรใช้spl_autoload_register(...)วันนี้ ... PS2: อย่าเข้าใจฉันผิดฉันใช้ฟังก์ชัน autoload ในบางครั้ง; )
jave.web

6

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

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

สิ่งที่ฉันได้เห็นว่าไม่ดีจริง ๆ คือเมื่อกรอบขนาดใหญ่เสาหินใช้require_once()ในวิธีที่ผิดทั้งหมดโดยเฉพาะอย่างยิ่งในสภาพแวดล้อมที่ซับซ้อนเชิงวัตถุ (OO)

นำตัวอย่างการใช้require_once()ที่ด้านบนของทุก ๆ คลาสตามที่เห็นในไลบรารีจำนวนมาก:

require_once("includes/usergroups.php");
require_once("includes/permissions.php");
require_once("includes/revisions.php");
class User{
  // User functions
}

ดังนั้นUserคลาสจึงได้รับการออกแบบให้ใช้คลาสอื่นทั้งสามคลาส ยุติธรรมพอ!

แต่ตอนนี้จะเกิดอะไรขึ้นถ้าผู้เข้าชมเรียกดูไซต์และไม่ได้ล็อกอินและโหลดเฟรมเวิร์ก: require_once("includes/user.php");สำหรับทุกคำขอ

มันรวมถึง 1 + 3 คลาสที่ไม่จำเป็นซึ่งไม่เคยใช้ในระหว่างการร้องขอนั้น นี่คือวิธีที่เฟรมเวิร์กสิ้นสุดลงโดยใช้ 40 MB ต่อคำขอเมื่อเทียบกับ 5 MB หรือน้อยกว่า


วิธีอื่น ๆ ที่สามารถนำไปใช้ในทางที่ผิดได้คือเมื่อชั้นเรียนถูกนำมาใช้ซ้ำโดยผู้อื่นจำนวนมาก! สมมติว่าคุณมีคลาสประมาณ 50 คลาสที่ใช้helperฟังก์ชัน เพื่อให้แน่ใจว่าhelpersจะพร้อมใช้งานสำหรับคลาสเหล่านั้นเมื่อมีการโหลดคุณจะได้รับ:

require_once("includes/helpers.php");
class MyClass{
  // Helper::functions(); // etc..
}

ไม่มีอะไรผิดปกติที่นี่ต่อ se อย่างไรก็ตามหากคำขอหนึ่งหน้าเกิดขึ้นเพื่อรวม 15 คลาสที่คล้ายกัน คุณกำลังทำงานrequire_once15 ครั้งหรือเพื่อภาพที่ดี:

require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");

การใช้ require_once () มีผลกระทบทางเทคนิคต่อประสิทธิภาพการทำงานของฟังก์ชั่นนั้น 14 ครั้งโดยไม่จำเป็นต้องแยกวิเคราะห์บรรทัดที่ไม่จำเป็นเหล่านั้น มีเพียง 10 คลาสที่มีการใช้งานมากที่มีปัญหาที่คล้ายกันนั้นก็สามารถอธิบายได้ว่ามีรหัสซ้ำ ๆ กันมากกว่า 100 บรรทัด

ด้วยสิ่งนี้อาจเป็นประโยชน์require("includes/helpers.php");ที่ bootstrap ของแอปพลิเคชันหรือกรอบงานของคุณแทน แต่เนื่องจากทุกอย่างเป็นญาติมันทั้งหมดขึ้นอยู่ว่าน้ำหนักเมื่อเทียบกับความถี่ในการใช้งานของhelpersชั้นประหยัด 15-100 require_once()เส้นของมูลค่า แต่ถ้าความน่าจะเป็นที่จะไม่ใช้helpersไฟล์ในคำขอใด ๆ ที่ให้มานั้นไม่มีเลยดังนั้นrequireควรอยู่ในคลาสหลักของคุณแทน การมีrequire_onceชั้นเรียนแยกจากกันจะทำให้สิ้นเปลืองทรัพยากร


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


5

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

อัปเดต: เนื่องจากเวอร์ชันของเว็บที่เก็บถาวรของวิกินั้นดูน่าเกลียดมากฉันจึงคัดลอกสาเหตุที่น่าสนใจที่สุดด้านล่าง:

  • จำเป็นต้องมี include_path เพื่อใช้แพ็คเกจ (PEAR) สิ่งนี้ทำให้เป็นการยากที่จะรวมแพ็กเกจ PEAR ภายในแอ็พพลิเคชันอื่นด้วย include_path ของตัวเองเพื่อสร้างไฟล์เดียวที่มีคลาสที่ต้องการเพื่อย้ายแพ็กเกจ PEAR ไปยังไฟล์เก็บถาวร phar โดยไม่มีการแก้ไขซอร์สโค้ดที่กว้างขวาง
  • เมื่อระดับบนสุด require_once ถูกผสมกับ require_once แบบมีเงื่อนไขจะส่งผลให้โค้ดที่ไม่สามารถเข้าถึงได้โดยแคช opcode เช่น APC ซึ่งจะมาพร้อมกับ PHP 6
  • ญาติ require_once ต้องการที่ include_path ถูกตั้งค่าเป็นค่าที่ถูกต้องทำให้มันเป็นไปไม่ได้ที่จะใช้แพคเกจโดยไม่ต้องมี include_path ที่เหมาะสม

5

*_once()ฟังก์ชั่นstatไดเรกทอรีแม่ทุกคนเพื่อให้แน่ใจว่าไฟล์ที่คุณกำลังรวมทั้งจะไม่เหมือนกันเป็นหนึ่งที่ได้รับการรวมแล้ว นั่นเป็นส่วนหนึ่งของเหตุผลในการชะลอตัว

ฉันแนะนำให้ใช้เครื่องมืออย่างSiegeเพื่อการเปรียบเทียบ คุณสามารถลองวิธีการทั้งหมดที่แนะนำและเปรียบเทียบเวลาตอบสนอง

เพิ่มเติมเกี่ยวกับrequire_once()ที่เทคของจักรวาล


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

2

แม้ว่าrequire_onceและinclude_once จะช้ากว่าrequireและinclude(หรือมีทางเลือกอื่นใดก็ตาม) เรากำลังพูดถึงระดับที่เล็กที่สุดของการเพิ่มประสิทธิภาพขนาดเล็กที่นี่ require_onceเวลาของคุณคือการใช้จ่ายที่ดีมากในการเพิ่มประสิทธิภาพที่เขียนไม่ดีห่วงหรือฐานข้อมูลแบบสอบถามกว่ากังวลเกี่ยวกับสิ่งที่ชอบ

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

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


0

คุณทดสอบโดยใช้ include, ทางเลือกของ oli และ __autoload (); และทดสอบด้วยการติดตั้งAPC

ฉันสงสัยว่าการใช้ค่าคงที่จะทำให้ทุกอย่างเร็วขึ้น


0

ใช่มันมีราคาแพงกว่าแบบธรรมดา ol เล็กน้อย '() ฉันคิดว่าประเด็นคือถ้าคุณสามารถจัดระเบียบรหัสของคุณให้มากพอที่จะไม่ซ้ำกันรวมถึงอย่าใช้ * _once () ฟังก์ชั่นเพราะมันจะช่วยให้คุณประหยัดรอบ

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


-2

ฉันคิดว่าในเอกสารลูกแพร์มีคำแนะนำสำหรับต้องการ, require_once, รวมและ include_once ฉันทำตามแนวทางนั้น ใบสมัครของคุณจะชัดเจนยิ่งขึ้น


การอ้างอิงบางอย่างจะอยู่ในลำดับ
Peter Mortensen

-3

มันไม่เกี่ยวอะไรกับความเร็ว มันเกี่ยวกับความล้มเหลวอย่างงดงาม

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


1
ไม่จำเป็น. จริงๆคุณสามารถขอในตัวจัดการข้อผิดพลาดหรือในตัวจัดการการปิดเพื่อให้ผู้ใช้หน้าข้อผิดพลาดที่ดี (แม้ว่าคนไม่ค่อยทำ) ในฐานะนักพัฒนาฉันจะทำสิ่งต่าง ๆ ผิดพลาดทันที
Edward Z. Yang

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

-4

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

คุณควรรู้ว่าคุณจำเป็นต้องมีไฟล์หรือไม่

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