Files
XC_VM/docs/en/development/autoloader.md
T

145 lines
4.5 KiB
Markdown

# Autoloader — Class Registration
XC_VM uses a custom autoloader (`src/autoload.php`) instead of Composer.
Classes are discovered **automatically** — no manual registration required.
---
## How It Works
```
Request → autoload.php included
│
├── Cache file exists?
│ YES → load igbinary cache → O(1) lookups
│ NO → warmCache(): scan all directories via token_get_all()
│ → build ClassName → filePath map
│ → persist to tmp/cache/autoload_map
│
└── Class requested by PHP
│
├── 1. Explicit classMap (addClass())
├── 2. Resolved cache (from file or previous lookup)
└── 3. Live directory scan (fallback, cached for next time)
```
## Adding a New Class
**Just create the file.** That's it.
Place your PHP file in any registered directory (or its subdirectory):
| Directory | Purpose |
|-----------|---------|
| `src/core/` | Framework core (Database, Cache, Auth, Http, Process, etc.) |
| `src/domain/` | Business logic (Services, Repositories) |
| `src/infrastructure/` | External adapters (DatabaseFactory, CacheReader, Redis) |
| `src/streaming/` | Streaming subsystem (Auth, Delivery, Codec, Health) |
| `src/modules/` | Optional modules (Plex, Watch, TMDB, Ministra, etc.) |
| `src/public/` | Controllers and Views |
### Example
```php
// src/domain/Billing/InvoiceService.php
class InvoiceService {
public static function generate($userId) { ... }
}
```
After creating the file, **delete the cache** so the autoloader rediscovers classes:
```bash
rm -f /home/xc_vm/tmp/cache/autoload_map
```
On the next request, `warmCache()` runs automatically, finds `InvoiceService`, and caches it.
## Cache Invalidation
The cache file `tmp/cache/autoload_map` is a binary file (igbinary format).
It must be deleted whenever:
- A new class file is added
- A class file is renamed or moved
- A class file is deleted
```bash
# Delete manually
rm -f /home/xc_vm/tmp/cache/autoload_map
# Or via PHP
XC_Autoloader::clearCache();
```
> **Note:** If a class is requested that isn't in the cache, the autoloader falls back to a live directory scan and caches the result automatically. So the cache only needs to be cleared when files are moved/renamed/deleted — new classes will eventually be found via fallback.
## Manual Registration (Rare)
For special cases where a file contains multiple classes or the filename doesn't match the class name:
```php
XC_Autoloader::addClass('DropboxClient', '/home/xc_vm/includes/libs/Dropbox.php');
XC_Autoloader::addClass('DropboxException', '/home/xc_vm/includes/libs/Dropbox.php');
```
This is mainly needed for legacy library files that bundle multiple classes in one file (e.g., `iptables.php`, `m3u.php`).
## Adding a New Source Directory
Edit `registerDirectories()` in `src/autoload.php`:
```php
private static function registerDirectories() {
$base = self::$basePath;
self::addDirectory($base . 'core');
self::addDirectory($base . 'domain');
self::addDirectory($base . 'infrastructure');
self::addDirectory($base . 'streaming');
self::addDirectory($base . 'modules');
self::addDirectory($base . 'public');
// Add your new directory here:
self::addDirectory($base . 'my_new_dir');
}
```
Then delete the cache.
## Naming Rules
| Rule | Example |
|------|---------|
| File name **must** match class name | `InvoiceService.php` → `class InvoiceService` |
| One class per file (recommended) | Multi-class files need `addClass()` |
| PascalCase | `StreamService`, `DatabaseHandler` |
| No namespaces | `class StreamService { }` — no `namespace` keyword |
| No `declare(strict_types=1)` | Project convention |
## Duplicate Class Names
If two files define the same class name, **first-found wins** based on directory scan order. This is fragile — avoid duplicate names. Use prefixed names instead:
```
✗ public/Controllers/Admin/PlexController.php ← conflict
✗ modules/plex/PlexController.php ← conflict
✓ public/Controllers/Admin/AdminPlexController.php ← unique
✓ modules/plex/PlexController.php ← unique
```
## Debugging
```php
// See all registered directories
print_r(XC_Autoloader::getDirectories());
// See explicit class map
print_r(XC_Autoloader::getClassMap());
// Force full rescan
XC_Autoloader::clearCache();
XC_Autoloader::warmCache();
```