3

上一个问题显示了如何强制自动加载所有类。

但是我需要自己强制自动加载一个类。我怎么能那样做?

它不能:

  • 涉及更改类的源代码
  • 依赖于类源代码的任何部分(方法、变量、修饰符,例如,它必须可以自由地从具体变为抽象而不影响这一点)。

此外,最好不涉及将类的名称编码为字符串。(帮助 IDE 重构等)。

到目前为止我发现的最好的选择就是使用spl_autoload_call()

spl_autoload_call("Jodes\\MyClass");

或对于非命名空间类:

spl_autoload_call("MyClass");
4

2 回答 2

2

我最近也有同样的需求。这样做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);
于 2017-06-04T21:25:44.710 回答
0

我对此采取了不同的方法,可能不是最好的,但它是对我有意义的最好的方法之一。然而,它确实涉及修改源代码,但实现起来非常简单。

我通常有一个恰当命名的初级班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.

有些人可能会为此打我一巴掌,但我个人认为这是一种相对体面的方式来完成你想要的,尽管不是你通常喜欢的方法(不更改代码)。

还可以方便地为您正在制作的任何内容创建插件:)

于 2015-08-09T04:37:09.880 回答