Принудительная автозагрузка определенного класса

Этот предыдущий вопрос показывает, как заставить автозагрузку всех классов.

Однако мне нужно заставить автозагрузку только одного класса самостоятельно. Как я мог это сделать?

Это не должно:

  • Привлекать изменение исходного кода класса
  • Положитесь на любую часть исходного кода класса (методы, переменные, модификаторы, например, он должен быть свободным, чтобы переходить от конкретного к абстрактному, не влияя на это).

Кроме того, предпочтительно, чтобы оно не включало в себя кодирование имени класса в виде строки. (Чтобы помочь с рефакторингом IDE и так далее).

Лучший вариант, который я нашел до сих пор, это просто использовать spl_autoload_call():

spl_autoload_call("Jodes\\MyClass");

или для классов без пространства имен:

spl_autoload_call("MyClass");

3

Решение

У меня была такая же потребность в последнее время. дела require_once это был не вариант, потому что автозагрузчик действительно должен был найти класс из-за некоторых более сложных правил, поэтому невозможно было точно узнать путь к файлу с классом.

Хотя функция spl_autoload_call($classname) предназначен именно для этого, он страдает от фундаментального недостатка: он бросит ФАТАЛЬНАЯ ОШИБКА в случае, если вы вызываете его дважды для одного и того же имени класса или даже если некоторые из дочерних классов этого класса уже были загружены. Это происходит потому, что невозможно переопределить классы в 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);
1

Другие решения

Я использовал другой подход к этому, возможно, не самый лучший, но это один из лучших вариантов, который имел для меня смысл. Тем не менее, он требует модификации исходного кода, но его довольно просто реализовать.

У меня обычно есть первичный класс, названный точно 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.

Некоторые люди, вероятно, дали бы мне пощечину за это, но лично я думаю, что это относительно приличный способ выполнить то, что вы хотите, хотя не в методе, который вы обычно предпочитаете (не изменяя код).

Также удобно, чтобы плагин можно было создавать для всего, что вы делаете 🙂

0

По вопросам рекламы [email protected]