@Aqulus

Не получается загрузить класс через spl_autoload_register, как исправить?

Решил сделать свою MVC, но без использования Composer Namespace. Решил пойти по пути Zend'a и сделать неймспейсы в названиях классов. Проблема началась тогда, когда я захотел реализовать расширения для MVC, чтобы было легко добавлять "плагины" без влезания в основной код.

Позаимствовав extendClass у движка XenForo, я получил класс для расширений, но вот проблема в том, что при попытке сделать class_exists, я получаю ошибку, что нет такого класса, получается, spl_autoload_register не видит этот класс при попытке сделать class_alias с виртуальным классом.

Ошибка:
Could not find class MyAddon_Application_Controller_Pub_Index when attempting to extend Application_Controller_Pub_Index

Проблема еще заключается в том, что в Extension.php я делаю:
Application::autoload($outputClass);

			dump(Application::getAutoloader()->getLoadedClasses());

			if (!class_exists($outputClass))
			{
				throw new \Exception("Could not find class $outputClass when attempting to extend $class");
			}


Вывод дампа:
^ array:2 [▼
  0 => "Application_Mvc_Extension"
  1 => "Application_Controller_Pub_AbstractController"
]


По какой-то причине тут нет "MyAddon_Application_Controller_Pub_Index".
Очень надеюсь, что есть те, кто помогут. Потому что для меня это выглядит как какая-то магия

Структура проекта:
653b5a823c4fe089206249.png

Код autoloader'a:
<?php

class Application_Autoload
{
	protected $loadedClasses;
	protected static $_instance;

	public function __construct()
	{
		spl_autoload_register([$this, 'autoloader']);
	}

	public static final function getInstance(): Application_Autoload
	{
		if (!self::$_instance)
		{
			self::$_instance = new self();
		}

		return self::$_instance;
	}

	public function getLoadedClasses()
	{
		return $this->loadedClasses;
	}

	/**
	 * @throws Exception
	 */
	public function autoloader($class, $type = null): bool
	{
		$this->loadedClasses[] = $class;

		if (!$class)
		{
			return false;
		}

		if (class_exists($class, false) || interface_exists($class, false))
		{
			return true;
		}

		if (substr($class, 0, 5) == 'XFCP_')
		{
			throw new \Exception('Cannot load class using XFCP. Load the class using the correct loader first.');
		}

		$filename = $this->autoloaderClassToFile($class, $type);

		if (!$filename)
		{
			return false;
		}

		if (file_exists($filename))
		{
			include($filename);

			return (class_exists($class, false) || interface_exists($class, false));
		}

		return false;
	}

	public function autoloaderClassToFile($class, $type)
	{
		if (preg_match('#[^a-zA-Z0-9_\\\\]#', $class))
		{
			return false;
		}

		$srcPath = $type ? '/src/addons/' : '/src/';

		return str_replace(['_', '\\'], '/', Application::getRootDirectory()) . $srcPath . str_replace(['_', '\\'], '/', $class) . '.php';
	}
}


Код Application.php(точка входа приложения, вызывается start() из index.php):
// ...
	public static function getExtensions(): array
	{
		return [
			'Application_Controller_Pub_Index' => [
				'MyAddon_Application_Controller_Pub_Index'
			]
		];
	}

	/**
	 * @throws Exception
	 */
	public static function start($rootDirectory): void
	{
		set_error_handler(['Application', 'errorHandler']);
		register_shutdown_function(['Application', 'fatalHandler']);
		set_exception_handler(['Application', 'exceptionHandler']);

		ini_set('display_errors', 0);
		ini_set('error_reporting', E_ALL);

		self::$time = time();
		self::$rootDirectory = $rootDirectory;
		self::$autoloader = new Application_Autoload();

		foreach (Application::getExtensions() as $baseClass => $fakeClass)
		{
			self::extendClass($baseClass, $fakeClass);
		}

		self::$router = new Application_Mvc_Router();
	}

	/**
	 * @throws Exception
	 */
	public static function extendClass($extendClass, $fakeClass = null)
	{
		$a = new Application_Mvc_Extension(self::getExtensions());

		return $a->extendClass($extendClass, $fakeClass);
	}

	public static function autoload($class)
	{
		return Application_Autoload::getInstance()->autoloader($class);
	}

// ...


Код Extension.php:
<?php

class Application_Mvc_Extension
{
	protected $classExtensions = [];

	public function __construct(array $classExtensions = [])
	{
		$this->classExtensions = $classExtensions;
	}

	/**
	 * @throws Exception
	 */
	public function extendClass($class, $type = '', $fakeBase = false)
	{
		if (!$class)
		{
			return false;
		}

		$extensions = !empty($this->classExtensions[$class]) ? $this->classExtensions[$class] : [];
		if (!$extensions)
		{
			return $class;
		}

		$outputClass = $class;
		Application::autoload($outputClass);

		foreach ($extensions as $baseClass => $extendClass)
		{
			if (preg_match('/[;,$\/#"\'\.()]/', $extendClass))
			{
				continue;
			}

			$proxyClass = 'XFCP_' . $extendClass;

			class_alias($outputClass, $proxyClass);
			$outputClass = $extendClass;

			Application::autoload($outputClass);

			if (!class_exists($outputClass))
			{
				throw new \Exception("Could not find class $outputClass when attempting to extend $class");
			}
		}

		$this->classExtensions[$class] = $outputClass;

		Application::autoload($outputClass);

		return $outputClass;
	}
}


src/addons/MyAddon/Application/Controller/Pub/Index.php:
<?php

class MyAddon_Application_Controller_Pub_Index extends XFCP_Application_Controller_Pub_Index
{
	public function __construct()
	{
		echo 'constructor';
	}

	public function actionIndex($params)
	{
		echo 'extend class';
	}
}

if (false)
{
	class MyAddon_Application_Controller_Pub_Index extends Application_Controller_Pub_Index
	{
	}
}
  • Вопрос задан
  • 131 просмотр
Решения вопроса 1
@Aqulus Автор вопроса
Решил проблему тем, что перешёл на неймспейсы и в своём extension.php отдельно(независимо от composer autoloader'a) подключал файлы плагинов.

spl_autoload_register(function ($class)
				{
					$path = str_replace('\\', '/', \Application::getRootDirectory() . '/src/addons/' . $class . '.php');

					if (!file_exists($path))
					{
						throw new \Exception("Файл расширения {$class} по пути {$path} не найден!");
					}
					else
					{
						require $path;
					}
				});


Спасибо Дмитрий !
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы