Files
XC_VM/docs/en/development/exception-hierarchy.md
T
Divarion_D c982bb2f1e docs: audit dev docs for source drift, split oversized pages, add core-wiring
Verify every dev-doc claim against src/ and fix factual drift: wrong method
signatures/return types, wrong enum casing (BootContext cases are PascalCase),
stale paths (M3u parsers are Composer deps under vendor/, MobileDetect is
mobiledetect/mobiledetectlib v4.9.0 \Detection\MobileDetect, NotFoundException
lives in XcVm\Core\Container\Psr), a fictional `stream:check` command/class,
reversed migration-failure semantics ([FAIL] = not recorded, retried),
inverted isStreamRunning/isStreamAlive descriptions, findProcessPIDs ANY-not-ALL,
acquireCronLock has no shutdown callback, and nonexistent make targets.

Split oversized pages and fix nav + cross-links:
- modules.md -> module-authoring / module-lifecycle / module-extension-points
- cli-tools.md -> cli-tools + database-migrations
- streaming-subsystem.md -> + streaming-diagnostics
- geoip-and-device-detection.md -> geoip-isp-and-geo-routing + device-detection-and-stb-locking

Add development/core-wiring.md: how the core assembles itself at boot
(container population, ServiceContainer reference, bootAll orchestration,
CLI command auto-discovery, end-to-end Admin/CLI boot walkthroughs).

Only docs/en + mkdocs.yml touched; docs/ru is regenerated before release.
2026-08-26 22:42:43 +03:00

4.5 KiB

Exception Hierarchy

XC_VM's framework exceptions extend XcVmException — an empty marker base (class XcVmException extends \RuntimeException {}, it adds no extra data) — so callers can catch the whole family with one catch (XcVmException) or target a specific subsystem.

Scope. This typed hierarchy covers the DI container and module system only. It is not the whole panel: streaming/auth endpoints report failures through generateError() (not exceptions), and much domain/CLI code throws plain \RuntimeException or SPL exceptions — those still match catch (XcVmException) only when the class actually extends it.


Tree

\Exception
└── \RuntimeException
    └── XcVmException
        ├── Container
        │   └── ContainerException      (PSR-11 ContainerExceptionInterface)
        │       ├── CircularDependencyException
        │       ├── ServiceCreationException
        │       └── NotFoundException   (PSR-11 NotFoundExceptionInterface) *
        └── Module
            └── ModuleException
                ├── ModuleNotFoundException
                ├── ModuleLoadException
                ├── ModuleManifestException
                └── ModuleCycleException

* NotFoundException extends ContainerException (so it belongs in this tree), but it physically lives at src/Core/Container/Psr/NotFoundException.php under the namespace XcVm\Core\Container\Psr — not in Core/Exception/Container/.


Container exceptions

Class When thrown
ContainerException Base for all container failures
CircularDependencyException A service's factory graph contains a cycle
ServiceCreationException Factory callable threw while creating a service
NotFoundException get($id) called for an unregistered service

NotFoundException implements both PSR-11 interfaces so the container is compliant:

try {
    $service = $container->get('unknown');
} catch (NotFoundException $e) {
    // PSR-11 NotFoundExceptionInterface
}

Module exceptions

Class When thrown
ModuleException Base for all module failures
ModuleNotFoundException Required dependency module is missing
ModuleLoadException Module file cannot be loaded or class not found
ModuleManifestException module.json is missing, malformed, or fails validation
ModuleCycleException Dependency graph has a cycle — thrown by ModuleLoader's topological sort with the cycle path (a -> b -> a) in the message. (Some @throws docblocks say \RuntimeException; that's just the base type — ModuleCycleException extends it via XcVmException.)

Catching by subsystem

// Catch any XC_VM exception
try {
    $loader->loadAll();
} catch (XcVmException $e) {
    logger()->error($e->getMessage());
}

// Catch only module-related failures
try {
    $loader->loadAll();
} catch (ModuleException $e) {
    // ModuleNotFoundException | ModuleLoadException | ...
}

// Catch container-specific failures
try {
    $container->get('missing');
} catch (ContainerException $e) {
    // CircularDependencyException | NotFoundException | ...
}

Adding or choosing an exception

  • Which to throw: use the most specific existing type (e.g. ModuleManifestException for a bad module.json). If nothing fits and it's a framework-level failure, throw XcVmException (or a new subclass) so it stays catchable as one family. Domain/business errors that aren't framework concerns may throw a plain \RuntimeException / \InvalidArgumentException.
  • Adding a category: create the class under src/Core/Exception/<Subsystem>/, extend the subsystem base (ContainerException / ModuleException) — or XcVmException for a new subsystem — and add it to the tree above. No registration is needed; it's plain PHP.

Location

src/Core/Exception/
├── XcVmException.php
├── Container/
│   ├── ContainerException.php
│   ├── CircularDependencyException.php
│   └── ServiceCreationException.php
└── Module/
    ├── ModuleException.php
    ├── ModuleNotFoundException.php
    ├── ModuleLoadException.php
    ├── ModuleManifestException.php
    └── ModuleCycleException.php
File Role
src/Core/Exception/ Exception base classes and the project hierarchy