Files
novaconium/novaconium/autoload.php
T
code fbd4e92e9f Replace v1 with v2 codebase
Full rewrite: swap out the v1 framework (src/, controllers/, views/,
twig/, sass/, skeleton/) for the working v2 codebase from phpproject
(App/, novaconium/, public/).
2026-07-14 01:58:25 +00:00

97 lines
4.1 KiB
PHP

<?php
/**
* Manual PSR-4 autoloader (no Composer).
*
* There's no vendor/autoload.php here — this file *is* the autoloader.
* `spl_autoload_register()` below registers a callback that PHP invokes
* automatically the first time an unknown class/namespace is referenced
* (e.g. `new Router(...)` or `use Lib\Mailer;`), so nothing else in this
* project ever has to manually `require` a class file.
*
* Two different resolution strategies live in that one callback:
* - `Twig\` and `App\` are plain one-directory-per-namespace PSR-4 (see
* $__psr4_prefixes below) — no override behavior, just a straight
* namespace-to-path mapping.
* - `Lib\` is resolved against an *ordered list* of directories (see
* $__lib_dirs below) — the first one where the file exists wins. This
* is what lets a project drop a same-named class into `App/lib/` to
* override a `novaconium/lib/` default, without editing novaconium/ at
* all — the same App-over-novaconium pattern used for pages/layouts
* (see Overlay.php) and Sass colors, just implemented here instead.
*/
// Straight namespace -> directory mapping, one entry per prefix. No
// override list here because neither of these is meant to be replaced by
// a project: Twig is vendored framework code, and App\ is the framework's
// own core classes (Router, Renderer, Cache, etc.) — see
// novaconium/src/. (A project's own code goes under Lib\, below.)
$__psr4_prefixes = [
'Twig\\' => __DIR__ . '/vendor/twig/src/',
'App\\' => __DIR__ . '/src/',
];
// Lib\ is resolved against App/lib first so a project can add/override
// classes, falling back to novaconium's default lib/ when not found there.
// Order matters: this array is walked top-to-bottom and the first file
// that actually exists on disk wins, so App/lib/ always gets first look.
$__lib_dirs = [
__DIR__ . '/../App/lib/',
__DIR__ . '/lib/',
];
// The callback PHP calls whenever a referenced class hasn't been loaded
// yet. It only ever needs to `require` the right file (or silently return
// if nothing matches, which just leaves the class undefined and PHP throws
// its own "Class not found" error) — there's no class map to build or
// cache, since every lookup is a cheap `is_file()` check against a handful
// of candidate paths.
spl_autoload_register(function (string $class) use (&$__psr4_prefixes, &$__lib_dirs): void {
// Lib\Foo\Bar -> try App/lib/Foo/Bar.php, then novaconium/lib/Foo/Bar.php.
if (str_starts_with($class, 'Lib\\')) {
$relative = substr($class, strlen('Lib\\'));
foreach ($__lib_dirs as $baseDir) {
$file = $baseDir . str_replace('\\', '/', $relative) . '.php';
if (is_file($file)) {
require $file;
return;
}
}
return;
}
// Twig\Foo\Bar -> novaconium/vendor/twig/src/Foo/Bar.php,
// App\Foo\Bar -> novaconium/src/Foo/Bar.php.
// Only one prefix can ever match (they don't overlap), so the loop
// just finds which one applies and returns right after handling it.
foreach ($__psr4_prefixes as $prefix => $baseDir) {
if (!str_starts_with($class, $prefix)) {
continue;
}
$relative = substr($class, strlen($prefix));
$file = $baseDir . str_replace('\\', '/', $relative) . '.php';
if (is_file($file)) {
require $file;
}
return;
}
});
// Twig 3.x calls trigger_deprecation() (normally provided by symfony/deprecation-contracts,
// which we don't vendor). Provide the same signature so deprecated code paths don't fatal.
// This has nothing to do with class autoloading above — it's defined here
// simply because this file already runs on every request before Twig does,
// making it a convenient, guaranteed-to-run-first place for the shim to live.
if (!function_exists('trigger_deprecation')) {
function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void
{
@trigger_error(
($package || $version ? "Since $package $version: " : '') . ($args ? vsprintf($message, $args) : $message),
E_USER_DEPRECATED
);
}
}