簡體   English   中英

強制自動加載特定類

[英]Force autoloading of a specific class

上一個問題顯示了如何強制自動加載所有類。

但是我需要自己強制自動加載一個類。 我怎么能那樣做?

它不能:

  • 涉及更改類的源代碼
  • 依賴於類源代碼的任何部分(方法、變量、修飾符,例如,它必須可以自由地從具體變為抽象而不影響這一點)。

此外,最好不涉及將類的名稱編碼為字符串。 (幫助 IDE 重構等)。

到目前為止,我發現的最佳選擇是只使用spl_autoload_call()

spl_autoload_call("Jodes\\MyClass");

或對於非命名空間類:

spl_autoload_call("MyClass");

我最近也有同樣的需求。 執行require_once不是一個選項,因為由於一些更復雜的規則,自動加載器確實需要定位該類,因此無法確切知道該類文件的路徑。

盡管函數spl_autoload_call($classname)正是為了做到這一點而設計的,但它存在一個基本缺陷:如果您為同一個類名調用兩次,或者即使該類的某些子類被調用,它也會拋出一個FATAL ERROR 。已經加載。 發生這種情況是因為無法在 PHP 中重新聲明類:

<?php

spl_autoload_call('TheClass');
// no problem

spl_autoload_call('TheClass');
// PHP Fatal error:  Cannot declare class TheClass, because the name is already in use in ... on line ...

我對這個問題的解決方案是不依賴class_exists($classname)的副作用,它不是為此目的而設計的,而是更可配置的,因此,提供了更多關於觸發自動加載器的控制。

更好的是,它在多次調用或繼承鏈中已經加載某些內容時絕對沒有問題。 如果類還沒有,它只是具有需要文件的副作用(如果你想要的話)!

<?php

class_exists('TheClass');
// no problem

class_exists('TheClass');
// already exists. No need to autoload it and no fatal errors!

有了這個,您就有了一種安全且冪等的方式來通過自動加載器加載類。

而且,如果您不想在其中使用類名對字符串進行硬編碼,從 PHP 5.5 版開始,您可以使用::class偽常量,它在編譯時解析為具有完全限定類名的字符串(包括命名空間):

<?php

class_exists(TheClass::class);

我對此采取了不同的方法,可能不是最好的方法,但它是對我來說最有意義的方法之一。 它確實涉及修改源代碼,但實現起來非常簡單。

我通常有一個名為Core的主要類

<?php
require_once("{$_SERVER['DOCUMENT_ROOT']}\Matilda\class\Settings.class.php");
require_once("{$_SERVER['DOCUMENT_ROOT']}\Matilda\class\Auth.class.php");
require_once("{$_SERVER['DOCUMENT_ROOT']}\Matilda\class\Permissions.class.php");
require_once("{$_SERVER['DOCUMENT_ROOT']}\Matilda\class\Procedures.class.php");
require_once("{$_SERVER['DOCUMENT_ROOT']}\Matilda\class\Audit.class.php");

class Core {

    /**
     * @var External class
     */
    public $Settings,$Sql,$Auth,$Permissions,$Payroll,$Customers,$Plans,$Billing,$Engin,$AAPT,$Stock,$Prospects,$Freeside,$Audit;

    /**
     * @var Base Config
     */
    private $InitConfig = array(
        'Payroll'           => false,
        'Customers'     => false,
        'Plans'             => false,
        'Billing'           => false,
        'Engin'             => false,
        'AAPT'          => false,
        'Stock'             => false,
        'Prospects'         => false,
        'Freeside'      => false,
    );

    public function __construct($Config = array()) {    
        // Session instantiation
        if (!isset($_SESSION)) session_start();

        if (!is_array($Config)) die('Core instantiation parameter must be an array, even if its empty');
        $this->InitConfig = array_merge($this->InitConfig, $Config);

        // Base classes
        $this->Settings             = new Settings();
        $this->Sql                  = new MySQLi(/* Mysql info */)
        $this->Audit                = new Audit($this->Settings, $this->Sql);
        $this->Auth                 = new Auth($this->Settings, $this->Sql, $this->Audit);
        $this->Permissions          = new Permissions($this->Settings, $this->Sql, $this->Auth, $this->Audit);

        // Optional class handling
        foreach ($this->InitConfig as $Dependency => $State) {
            if ($State == true) {
                require_once($this->Settings->RootDir . "/class/{$Dependency}.class.php");
                $this->$Dependency = new $Dependency($this->Settings, $this->Sql, $this->Auth, $this->Permissions, $this->Audit);
            }
        }

    }

這幾乎說明了我如何提供可選的加載配置。

它具有所需的5個默認類,因此無論如何總是加載:設置,身份驗證,權限,過程和審計

然后我可以實例化可選類: $Core = new Core(array('Payroll' => true)) ,它將實例化Payroll.class.php並可通過$Core->Payroll

這幾乎是存儲樹級功能的好方法

 $Core->Members->FetchMemberByID($ID);
 $Core->Plans->CreateNewPlan($PlanName, $Monthly, $Attributes = array())
 etc etc.

有些人可能會為此拍打我,但我個人認為這是一種相對不錯的方式來實現你想要的,雖然不是你通常喜歡的方法(不改變代碼)。

同樣方便的是允許為你正在制作的任何東西創建插件:)

我遇到了完全相同的問題並嘗試了不同的自動加載功能。 在 Windows PHP 8.1.5 版本上,我有這兩種不同的自動加載器:

set_include_path(get_include_path() . PATH_SEPARATOR . 'class/');
spl_autoload_extensions('.class.php');
spl_autoload_register();

或者

$autoloader = function( string $class_name )
{
  $filename = $_SERVER["DOCUMENT_ROOT"].'/class/' . str_replace( '\\', '/', $class_name)    . '.class.php';
  require_once $filename;
};

// our class loader
spl_autoload_register( $autoloader );

這似乎做同樣的事情。

由於我的應用程序中的一個類文件還創建了一些可在構建所述類期間使用的支持全局函數變量,因此我需要在訪問所述函數變量和構造之前強制加載類文件。 我用特定類的class_exist()做到了這一點。

使用spl_auoload_extenions版本效果很好; 使用spl_autoload_register($autoloader)版本會在使用函數變量時導致未定義的變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM