Этот предыдущий вопрос показывает, как заставить автозагрузку всех классов.
Однако мне нужно заставить автозагрузку только одного класса самостоятельно. Как я мог это сделать?
Это не должно:
Кроме того, предпочтительно, чтобы оно не включало в себя кодирование имени класса в виде строки. (Чтобы помочь с рефакторингом IDE и так далее).
Лучший вариант, который я нашел до сих пор, это просто использовать spl_autoload_call()
:
spl_autoload_call("Jodes\\MyClass");
или для классов без пространства имен:
spl_autoload_call("MyClass");
У меня была такая же потребность в последнее время. дела 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);
Я использовал другой подход к этому, возможно, не самый лучший, но это один из лучших вариантов, который имел для меня смысл. Тем не менее, он требует модификации исходного кода, но его довольно просто реализовать.
У меня обычно есть первичный класс, названный точно 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.
Некоторые люди, вероятно, дали бы мне пощечину за это, но лично я думаю, что это относительно приличный способ выполнить то, что вы хотите, хотя не в методе, который вы обычно предпочитаете (не изменяя код).
Также удобно, чтобы плагин можно было создавать для всего, что вы делаете 🙂