初學 PHP 類的自動載入

ㅤㅤ發表於2018-10-23

在實際專案中,每個功能會被定義成一個類,並且每個類都會被放到單獨的一個PHP檔案中,在另外一個檔案中想要使用某一個類,就需要引入存放該類的類檔案.
類檔案的定義有幾個要求:

  • 類檔名以 .class.php 結尾.
  • 類檔名要與其中的類名一致.
  • 類檔案以及類的命名使用"大駝峰"命名法.
  • 類中方法與屬性使用"小駝峰"命名法.

./User.class.php 類檔案.

<?php

class User {
    private $name = "劉看山";
    private $age  = "4";

    public function getInfo(){
        return "我是{$this->name},我有{$this->age}歲了!";
    }
}

./index.php 檔案.

<?php
require_once "./User.class.php";

$userObj = new User();
echo $userObj->getInfo();//輸出"我是劉看山,我有4歲了!"

在上面這個例子中, ./index.php 檔案中的 require_once "./User.class.php"; 這個語句相當於把 ./User.class.php 類檔案中的程式碼賦值到了 ./index.php 檔案中,但是當真正做專案的時候,類檔案成百上千,不可能每一次都這樣手動來載入.

__autoload() 函式

注意,該函式在PHP 7.2.0中被廢棄了.
當在指令碼中呼叫本指令碼中不存在的類時, __autoload() 函式會被呼叫,有如下幾種情況:

  • new一個物件時.例如 $obj = new User();
  • 呼叫類中的靜態屬性或者靜態方法時.例如 $result = User::showMessage()
  • 繼承父類時.例如 class Staff extends Person{};
  • 實現介面時.這個還沒學過.

在該函式中要做兩件事情:

  • 拼裝一個類檔案的真實物理路徑.
  • 類檔案存在則包含之.

上文中的 ./User.class.php 類檔案保持不變.修改 ./index.php 檔案.

<?php
function __autoload($className) {
    //構建類檔案的真實路徑
    $filePath = "./$className.class.php";
    //如果類檔案存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

$userObj = new User();
echo $userObj->getInfo();//輸出"我是劉看山,我有4歲了!"

spl_autoload_register() 函式

使用該函式需要傳入一個回撥函式,這裡結合了回撥函式的知識點.上文中的 ./User.class.php 類檔案保持不變.修改 ./index.php 檔案.有三種寫法,如下所示.

<?php
spl_autoload_register(function ($className) {
    //構建類檔案的真實路徑
    $filePath = "./$className.class.php";
    //如果類檔案存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
});

$userObj = new User();
echo $userObj->getInfo();//輸出"我是劉看山,我有4歲了!"

或者寫成

<?php
$myFunc = function ($className) {
    //構建類檔案的真實路徑
    $filePath = "./$className.class.php";
    //如果類檔案存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
};//這裡有個坑,要注意記得加上分號

spl_autoload_register($myFunc);

$userObj = new User();
echo $userObj->getInfo();//輸出"我是劉看山,我有4歲了!"

或者寫成

<?php
function myFunc($className) {
    //構建類檔案的真實路徑
    $filePath = "./$className.class.php";
    //如果類檔案存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

spl_autoload_register("myFunc");

$userObj = new User();
echo $userObj->getInfo();//輸出"我是劉看山,我有4歲了!"

相比較於 __autoload() 函式, spl_autoload_register() 函式的優勢是可以註冊多個回撥函式,每個回撥函式可以對應不同的載入規則.下面做個記錄.
./User/User.class.php 檔案.

<?php

class User {
    private $name = "劉看山";
    private $age  = "4";

    public function getInfo(){
        return "我是{$this->name},我有{$this->age}歲了!";
    }
}

./Student/Student.class.php 檔案.

<?php

class Student {
    private $name = "劉看火";
    private $job  = "打妖怪";

    public function getInfo(){
        return "我是{$this->name},我的工作是{$this->job}";
    }
}

./Teacher/Teacher.class.php 檔案.

<?php

class Teacher {
    private $name = "劉看水";
    private $school  = "北京大學";

    public function getInfo(){
        return "我是{$this->name},我在{$this->school}任教";
    }
}

./index.php 檔案.

<?php
function myFunc1($className) {
    $filePath = "./User/$className.class.php";
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

function myFunc2($className) {
    $filePath = "./Student/$className.class.php";
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

function myFunc3($className) {
    $filePath = "./Teacher/$className.class.php";
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

spl_autoload_register("myFunc1");
spl_autoload_register("myFunc2");
spl_autoload_register("myFunc3");

$userObj = new User();
echo $userObj->getInfo();//輸出"我是劉看山,我有4歲了!"
$studentObj = new Student();
echo $studentObj->getInfo();//輸出"我是劉看火,我的工作是打妖怪"
$teacherObj = new Teacher();
echo $teacherObj->getInfo();//輸出"我是劉看水,我在北京大學任教"

上面這種寫法很繁瑣,最佳化一下.
./User/User.class.php , ./Student/Student.class.php , ./Teacher/Teacher.class.php 這三個檔案保持不變.修改 ./index.php 檔案.

<?php
spl_autoload_register(function ($className) {
    $filePaths = [
        "./User/$className.class.php",
        "./Student/$className.class.php",
        "./Teacher/$className.class.php",
    ];
    foreach ($filePaths as $filePath){
        if (file_exists($filePath)){
            require_once "$filePath";
        }
    }
});

$userObj = new User();
echo $userObj->getInfo();//輸出"我是劉看山,我有4歲了!"
$userObj = new Student();
echo $userObj->getInfo();//輸出"我是劉看火,我的工作是打妖怪"
$userObj = new Teacher();
echo $userObj->getInfo();//輸出"我是劉看水,我在北京大學任教"
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章