การโหลดอัตโนมัติคืออะไร คุณใช้ spl_autoload, __autoload และ spl_autoload_register ได้อย่างไร


203

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

spl_autoload_register ()ให้ทางเลือกที่ยืดหยุ่นมากขึ้นสำหรับคลาสการโหลดอัตโนมัติ ด้วยเหตุนี้การใช้__autoload ()จึงไม่สนับสนุนและอาจเลิกใช้หรือลบออกในอนาคต

แต่ฉันไม่สามารถคิดออกว่าจะใช้spl_autoloadและspl_autoload_register

คำตอบ:


334

spl_autoload_register() ช่วยให้คุณสามารถลงทะเบียนฟังก์ชั่นหลาย ๆ อย่าง (หรือวิธีการคงที่จากคลาส Autoload ของคุณเอง) ที่ PHP จะใส่ลงในสแต็ก / คิวและโทรตามลำดับเมื่อมีการประกาศ "คลาสใหม่"

ตัวอย่างเช่น:

spl_autoload_register('myAutoloader');

function myAutoloader($className)
{
    $path = '/path/to/class/';

    include $path.$className.'.php';
}

//-------------------------------------

$myClass = new MyClass();

ในตัวอย่างด้านบน "MyClass" เป็นชื่อของคลาสที่คุณพยายามสร้างอินสแตนซ์ PHP ส่งชื่อนี้เป็นสตริงไปspl_autoload_register()ซึ่งช่วยให้คุณสามารถเลือกตัวแปรและใช้เพื่อ "รวม" คลาส / ไฟล์ที่เหมาะสม . ดังนั้นคุณไม่จำเป็นต้องรวมคลาสนั้นผ่านทางคำสั่ง include / require ...

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

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

ตัวอย่าง:

spl_autoload_register('MyAutoloader::ClassLoader');
spl_autoload_register('MyAutoloader::LibraryLoader');
spl_autoload_register('MyAutoloader::HelperLoader');
spl_autoload_register('MyAutoloader::DatabaseLoader');

class MyAutoloader
{
    public static function ClassLoader($className)
    {
         //your loading logic here
    }


    public static function LibraryLoader($className)
    {
         //your loading logic here
    }

เกี่ยวกับspl_autoload , สถานะด้วยตนเอง:

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

ในทางปฏิบัติมากขึ้นหากไฟล์ทั้งหมดของคุณอยู่ในไดเรกทอรีเดียวและแอปพลิเคชันของคุณใช้ไม่เพียง แต่ไฟล์. php เท่านั้น แต่ไฟล์กำหนดค่าแบบกำหนดเองที่มีนามสกุล. inc เช่นกลยุทธ์หนึ่งที่คุณสามารถใช้คือเพิ่มไดเรกทอรีของคุณที่มีทั้งหมด ไฟล์ไปยัง PHP รวมถึงเส้นทาง (ผ่านset_include_path())
และเนื่องจากคุณต้องการไฟล์กำหนดค่าของคุณเช่นกันคุณจะใช้spl_autoload_extensions()เพื่อแสดงรายการส่วนขยายที่คุณต้องการให้ PHP ค้นหา

ตัวอย่าง:

set_include_path(get_include_path().PATH_SEPARATOR.'path/to/my/directory/');
spl_autoload_extensions('.php, .inc');
spl_autoload_register();

เนื่องจาก spl_autoload เป็นการใช้งานเริ่มต้นของ__autoload()วิธีเวทย์มนตร์ PHP จะเรียก spl_autoload เมื่อคุณลองและยกตัวอย่างคลาสใหม่

หวังว่านี่จะช่วย ...


35
นี่อาจเป็นหนึ่งในคำตอบที่ดีที่สุดในประวัติศาสตร์ของคำตอบที่เคย เคารพ. ฉันมีหนึ่งใน "OMG! ตอนนี้มันสมเหตุสมผลแล้ว!" ช่วงเวลาเพราะคุณเป็นคนดีของฉัน ฉันคิดว่าฉันอาจจะเริ่มแฟนคลับ
สูงเพียงธรรมดา

2
เพื่อให้คำตอบนี้เป็นคำตอบที่ดีที่สุดแม้กระทั่งในจักรวาลสำรองโปรดเพิ่ม spl_autoload ให้มากอืม "เป็นประโยชน์" (?) แปลงชื่อไฟล์ทั้งหมดเป็นตัวพิมพ์เล็ก (ดูความคิดเห็นของฉันที่ @user ด้านล่าง) ไม่สามารถใช้ spl_autoload_register () วานิลลาถ้าคุณชอบ CapitalLettersAndStuff ของคุณ
สูงเพียงธรรมดา

6
@ Just Plain High ฉันไม่มีปัญหานั้นและไฟล์คลาสทั้งหมดของฉันนั้นมีการให้อูฐ BTW นี่คือคำตอบที่ยอดเยี่ยม มันช่วยให้ฉันเข้าใจแนวคิดง่ายๆที่ฉันไม่สามารถเข้าใจได้จนกว่าฉันจะอ่านบทความนี้! บรรทัดของฉัน 85 (และเติบโต) รวมไฟล์ที่รวมไฟล์ class ทั้งหมดของฉันตอนนี้ 7 บรรทัด!
kyle

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

2
การใช้(และโดยทั่วไป) เป็นประโยชน์อย่างมากต่อการโหลดอย่างเกียจคร้านไม่รวมไฟล์ / คลาส? นี่เป็นนัยของคำตอบ แต่ไม่ได้ระบุไว้อย่างชัดเจน สำหรับฉันนี่คือข้อมูลสำคัญที่จะสมบูรณ์แบบสำหรับการรวมไว้ในคำตอบของคุณ! :)spl_autoload_register()__autoload()
rinogo

13

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

เพื่อแสดงพฤติกรรมนี้เพียงแค่สร้างไฟล์ชื่อ index.php:

<?php
spl_autoload_register();
var_dump(new Main\Application);

จากนั้นสร้างโฟลเดอร์ชื่อ Main ซึ่งอยู่ถัดจากไฟล์ index.php สุดท้ายสร้างไฟล์ชื่อ Application.php ที่อยู่ใน Main และวางโค้ดต่อไปนี้ลงไป:

<?php namespace Main;
class Application{}

9
หมายเหตุจากผู้เล่นซอของฉันกับทั้งหมดนี้: spl_autoload () - และทำให้ spl_autoload_register () - ชื่อไฟล์ที่จะแปลงเป็นตัวพิมพ์เล็ก (แม้จะมีการรายงานข้อผิดพลาดอ้อนวอนและออกเสียงลงคะแนนโกรธ) ซึ่งหมายความว่าคุณอาจกำลังมองหา "Main \ Application" แต่ spl_autoload กำลังมองหา "main \ application" ถ้าคุณชอบอูฐอย่างฉันคุณต้องเขียนฟังก์ชั่นของคุณเอง มีตัวอย่างเริ่มต้นที่ดีอยู่ที่นี่: github.com/ircmaxell/PHP-CryptLib/blob/…
เพียงแค่ธรรมดา High

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

1
spl_autoload_register()การใช้งานเริ่มต้นไม่สามารถหาชั้นเรียนที่สืบทอดมา ดังนั้นการใช้ค่าเริ่มต้นไฟล์และไดเรกทอรีตัวพิมพ์เล็กที่สะท้อนเส้นทางเนมสเปซทุกอย่างทำงานได้ดีเว้นแต่ฉันจะมีคลาสที่ขยายคลาสอื่น (พาเรนต์) PHP นั้นเกิดข้อผิดพลาดที่ไม่สามารถหาคลาส parent ได้แม้จะอยู่ในไดเรกทอรี / namespace เดียวกัน! สิ่งที่สับสนคือพบว่ามีเพียงชั้นเรียนระดับแรกเท่านั้นดังนั้นฉันจึงต้องใส่spl_autoload_register()กฎของฟังก์ชันที่ไม่ระบุตัวตนกับคนที่ 1 เพื่อที่จะรวมคลาสพ่อแม่ / คลาสที่สืบทอดมาด้วยตนเอง
เริ่ม

1

นี่คือวิธีที่ฉันใช้ Autoload ในตัวอย่างที่กำหนดฉันต้องการโหลดคลาสในรูปแบบ 3 ไดเรกทอรีที่แตกต่างกัน

function namespaceAutoload($rawClass){

$class = str_replace('\\', DIRECTORY_SEPARATOR, $rawClass);

$possiblePaths[] = '..\sys\class\file.php';
$possiblePaths[] = '..\sys\class\lib\file.php';
$possiblePaths[] = '..\sys\class\class.file.inc.php';

foreach ($possiblePaths as $templatePath) {
    $path = str_replace(["\\", "file"], [DIRECTORY_SEPARATOR, $class], $templatePath);
    if (file_exists($path)) {
        require_once "$path";
        break;
    }
} spl_autoload_register("namespaceAutoload"); 

ในตัวอย่างที่ได้รับ PHP จะค้นหาเนมสเปซ \ ในสามไดเรกทอรีนี้โดยใช้รูปแบบชื่อไฟล์ทั้งสามที่แตกต่างกัน

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