hoa/core
Hoa\Core is the foundational library of the Hoa modular PHP ecosystem, supplying autoloading, error and exception handling, event management, and shared utilities that other Hoa packages depend on. It provides a lightweight base for structured, extensible PHP applications.
Before writing a line of integration code, confirm you actually need this. hoa/core is archived, its last tagged release is from November 2015, it has no dependents on Packagist, and it predates PSR-4/PSR-11 adoption. It is not a Laravel package — there is no service provider, no facade, no config file, and no package discovery. In a current Laravel app it will fight Composer, not cooperate with it.
If you are here because a legacy module already depends on it, or you are evaluating it for a port, do this first:
composer require hoa/core:~1.15 (pin the exact 1.x tag from Packagist — it is flagged abandoned there) and a single index.php. Confirm it boots at all on your PHP version. Most of the 2015 code will emit deprecations or fatal on PHP 8.x.Core.php (the singleton and registerAutoloader() bootstrap), Autoloader.php (its spl_autoload_register implementation), Consistency.php (design-by-contract assertions), and Protocol.php (the hoa:// stream-wrapper registry). Event.php and Parameter.php are secondary.require_once __DIR__.'/vendor/hoa/core/Core.php';
\Hoa\Core::registerAutoloader();
Hoa\Core\Consistency — precondition/postcondition checks in a domain service or a legacy port:
use Hoa\Core\Consistency;
Consistency::assert(
Consistency::isInt($quantity) && $quantity > 0,
'Quantity must be a positive integer, got %s.',
$quantity
);
Everything else (hoa:// paths, the event bus, the parameter bag) duplicates something Laravel or Symfony already gives you with support and Octane safety. If that assessment is right for your case, stop here and use the native equivalent instead — you have lost nothing.Adapter-first, always. Treat hoa/core as an untrusted third-party boundary. Expose one small interface in your app (QuantityGuard, LegacyStreamResolver, etc.) with a single implementation that calls Hoa, and inject that. This lets you delete the dependency later by swapping the binding, and it keeps Hoa\Core\* imports out of your domain code.
Service provider as the only integration point. Register the autoloader and any hoa:// protocols in register(), and keep the provider conditional on a config flag so test environments and CI never touch it:
public function register(): void
{
if (! config('legacy.hoa.enabled')) {
return;
}
require_once base_path('vendor/hoa/core/Core.php');
\Hoa\Core::registerAutoloader();
$this->app->singleton(LegacyStreamResolver::class);
}
Resist the urge to add Hoa\Core to config/app.php providers globally.
Event bridge, one direction only. Hoa\Core\Event is a static channel/bucket bus. If a legacy module fires events you need in Laravel, forward them into the framework dispatcher rather than consuming Laravel events inside Hoa:
\Hoa\Core\Event::register(
'legacy.order.placed',
'app',
function ($bucket) {
event(new OrderPlaced($bucket->getData()));
}
);
Never make Laravel's dispatcher depend on Hoa's registry — it is process-global static state and will leak between requests.
Parameter bag as a config shim. Hoa\Core\Parameter is a nested key/value bag with ArrayAccess. Map it to a plain array once at the boundary (iterator_to_array-style flattening, or read specific keys) and pass arrays into your app. Do not let Hoa\Core\Parameter instances escape into controllers or jobs.
Stream protocol only when porting. Hoa\Core\Protocol::register($scheme, $wrapperClass) registers a PHP stream wrapper so file_get_contents('hoa://Library/...') resolves through Hoa's path configuration. If you are porting a legacy module that hardcodes hoa://, keep the protocol and add a thin resolver that also understands Storage::disk() paths. For greenfield code, use Laravel's filesystem disks — the stream abstraction buys you nothing here.
Consistency assertions belong in tests and domain guards, not controllers. Use them where you would otherwise write throw new InvalidArgumentException; in feature tests, prefer native assert(), Pest expectations, or Laravel validation, because Hoa's failures surface as Hoa\Core\Exception and will not match Laravel's validation error shape.
Strangler-fig migration. Port one call site at a time behind the adapter, run the legacy and native implementations side by side in a feature test, then delete the Hoa path. Given the package's age, plan for the whole dependency to be gone within a release cycle or two.
Consistency into app/Support/ with attribution is usually cheaper than installing the whole package.#[AllowDynamicProperties], curly-brace string offsets, create_function-era idioms in adjacent Hoa packages, and loose is_* checks that now emit warnings. Test on your exact runtime before committing.hoa:// fails silently. If the protocol is not registered, or Hoa\Core\Configuration does not define the expected roots (hoa://Application, hoa://Data, hoa://Library, hoa://Etc), file_get_contents returns false rather than throwing. Always check the return value and log the resolved path. Paths are case-sensitive.Hoa\Core is a singleton; Protocol and Event are static registries. Under Octane, Swoole, or even queue workers that boot once, registrations persist across requests and listeners accumulate. Re-register (and Event::unregister) per boot, or keep Hoa strictly out of long-lived workers.composer dump-autoload -o and --classmap-authoritative can behave unpredictably. If you can, skip registerAutoloader() and let Composer's PSR-4 mapping find the classes; verify the namespace-to-path mapping actually holds in your installed tag.Hoa\Core\Exception extends \Exception but carries none of the context Laravel's handler expects (no render, no HTTP status, no report). Catch Hoa\Core\Exception\Idle / Runtime / Logic at the adapter boundary and rethrow as InvalidArgumentException or RuntimeException so the default handler and your logs behave.Consistency::assert() messages include the raw expression, which is useful but noisy. Wrap assertions in a try/catch at the boundary and log the expression with a correlation ID if you are chasing a legacy failure."hoa/core": "1.15.x"), never a caret range, and commit the lockfile. There will be no 1.16.symfony/event-dispatcher or Laravel's own Dispatcher for events, symfony/options-resolver for parameter bags, league/flysystem for streams, webmozart/assert or native assertions for contract checks. Each is maintained, PSR-compliant, and safe under Octane — which hoa/core is not.How can I help you explore Laravel packages today?