Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Consistency Laravel Package

hoa/consistency

Hoa\Consistency is a foundational PHP library that helps code behave consistently across PHP versions and environments. It offers compatibility helpers, callable utilities, and environment detection, making it useful for Hoa packages and projects that need stable cross-version behavior.

View on GitHub
Deep Wiki
Context7

Getting Started

hoa/consistency is not a Laravel package. It is a low-level PHP utility library from the Hoa project that provides three main things: PHP feature detection helpers, a normalized callable wrapper (Xcallable), and entity/class-name resolution helpers. In a Laravel codebase its day-to-day value is narrow: use it when you are already inside the Hoa dependency tree, or copy the Xcallable pattern when you need reliable callable normalization.

The current line is 2.x, not 1.x. Release 2.17.08.29 (August 2017) is a major version bump with breaking changes, not a patch — see Gotchas before upgrading.

composer require hoa/consistency:^2.17

Do not blindly run composer update if you are on ^1.17: 1.x and 2.x are not drop-in compatible, and other Hoa packages may still constrain ~1.0. The last release was 2.17.08.29 in August 2017, and the repository is archived. Composer may warn that the package is abandoned. Pin the version and expect no upstream fixes.

Look first at (paths moved from src/ to Source/ in 2.x):

  • Source/Consistency.php — hasClass(), getClass(), hasFunction(), getFunction(), hasConstant(), isPhp(), enable(), curry().
  • Source/Xcallable.php — normalize strings, arrays, closures, and invokable objects into one callable type.
  • Source/FlexEntity.php — entity-name resolution used by Hoa’s class alias/flex conventions.
  • Source/Exception.php — the package exception type; as of 2.x it no longer extends Hoa\Exception\Exception (the hoa/exception dependency was dropped).
  • The autoloader wired up by Consistency::enable() — rewritten in 2.x to account for the Source move.

First useful use case: wrap a listener or callback so you can inspect, invoke, and re-bind it consistently.

use Hoa\Consistency\Xcallable;

$listener = new Xcallable([new SendInvoiceListener(), 'handle']);

echo $listener->getValidName(); // SendInvoiceListener::handle
$listener($order);              // invokes the method

A second use case is optional integration detection:

use Hoa\Consistency\Consistency;

if (Consistency::isPhp('8.1') && Consistency::hasFunction('array_is_list')) {
    // use the native function
}

Implementation Patterns

Normalize callables at your boundaries. If you accept callables from config, service providers, or event maps, wrap them once with Xcallable and pass the wrapper around internally. It implements __invoke, so Laravel’s dispatcher, queue callbacks, and higher-order helpers can still call it.

use Hoa\Consistency\Xcallable;

final class CallbackFactory
{
    public static function make(callable|string|array $callback): Xcallable
    {
        return new Xcallable($callback);
    }
}

$callback = CallbackFactory::make(fn ($payload) => logger($payload));
$callback(['event' => 'order.paid']);

Keep the wrapper behind your own small interface so a future replacement is a one-file change rather than a grep across the app.

Use Consistency for optional package detection, not for core Laravel features. Laravel already has class_exists(), function_exists(), and version_compare(). Consistency adds value mainly when you need the canonical resolved name, because PHP class names are case-insensitive but PSR-4 autoloading is not.

use Hoa\Consistency\Consistency;

$class = Consistency::getClass('app\\services\\billing\\stripe');

if (false !== $class) {
    // $class contains the resolved class name
}

Gate PHP features with isPhp() rather than scattered version_compare calls. isPhp('8.2') is a minimum-version check, not an exact-version check. Use it to choose between a native implementation and a fallback, then hide that decision behind a single method.

if (Consistency::isPhp('8.1')) {
    return array_is_list($value);
}

return array_keys($value) === range(0, count($value) - 1);

Use curry() knowing it was rewritten for 2.x. The 1.x implementation carried separate PHP 7.x code paths that were removed; curry() now relies on modern closure semantics only. It is still a Hoa-flavoured helper, not a general-purpose replacement for Laravel’s container resolution — if you need partial application, a locally owned helper is easier to reason about and to modernize.

Use Xcallable::bindTo() when re-scoping closures. This is useful when a closure is resolved from a container and must be rebound to a different object. Treat it as an advanced tool: rebinding changes $this and can surprise callers if the closure was not designed for it.

$x = new Xcallable($closure);
$bound = $x->bindTo($newContext);
$bound($argument);

Use distributeArgument() when forwarding by-reference arguments. PHP’s normal call_user_func_array() loses reference semantics in some paths. If you are writing a dispatcher or middleware that forwards arguments to an arbitrary callable, this helper exists specifically to respect ReflectionParameter by-reference flags.

Cache feature detection results. Consistency::hasClass() and friends do reflection-style checks. In a request lifecycle this is cheap, but in a loop or an Octane worker it is wasted work. Resolve once in a service provider or a small memoized helper.

Do not expose Xcallable in public APIs. Return callable from your own methods and keep Xcallable as an internal implementation detail. That prevents a future replacement from becoming a breaking change.

Gotchas and Tips

1.x → 2.x is a breaking upgrade, despite the 2017 date. The release notes list three concrete BC breaks worth checking before you bump the constraint:

  • Directory move. Code moved from src/ to Source/. Anything that references vendor file paths directly — a custom autoloader, a phpunit.xml coverage whitelist, an IDE path, a static-analysis config, or a require/include in a legacy bootstrap — must be updated.
  • hoa/exception dependency dropped. Hoa\Consistency\Exception no longer inherits from Hoa\Exception\Exception. Any catch (\Hoa\Exception\Exception $e) or catch (\Hoa\Consistency\Exception $e) written against 1.x semantics should be re-checked; the safe catch is \Throwable plus instanceof discrimination.
  • PHP 7.1 minimum; PHP 7.x workaround implementations removed. Old fallbacks inside the detection helpers and curry() are gone. That is fine for current Laravel, but a codebase still pinning an older runtime will fail.

Composer abandonment warning. You may see “Package hoa/consistency is abandoned.” That is expected. There are no security patches and effectively no community support. Pin an exact version in composer.json and commit the lock file.

Global bootstrap side effects. Consistency::enable() bootstraps compatibility aliases/shims and registers an autoloader. In 2.x that autoloader was rewritten to reflect the Source move, so an upgrade can silently change which paths get resolved. Call enable() once, early, and only if you actually need the shim layer. In long-running workers such as Laravel Octane, global aliases and autoloader registrations persist across requests. Avoid calling it repeatedly or conditionally inside request handlers.

getClass() can return false. Always compare strictly and handle missing classes. Do not pass the result directly into new or app().

Class-name resolution is not autoloading. getClass() helps once a class or alias is already known to PHP. It will not fix a PSR-4 path whose case does not match the file system. On Linux, a mismatch between App\Services\Foo and app/services/Foo.php is still an autoload failure.

isPhp() semantics. Verify your version’s behavior before relying on it: it is intended as “at least this version,” not “exactly this version.” If you need exact comparisons, use PHP_VERSION_ID directly. 2.x changed the implementations here, so re-run any test that asserted on the old fallback behaviour.

Do not serialize Xcallable instances. Closures and bound objects cannot be safely serialized. Do not store them in cache, session, or queued payloads. Rebuild callables from class strings or container identifiers when a job boots.

By-reference arguments are subtle. If you forward arbitrary callables, test with a function that takes &$value. distributeArgument() is the intended extension point, but verify argument ordering and default values with your exact PHP version.

FlexEntity is Hoa-specific. If you are not already using Hoa’s entity/class naming conventions, skip it. It is not a general replacement for Laravel’s container binding or class resolution.

Vendoring is a reasonable exit plan — and 2.x makes it cheaper. The library is small and permissively licensed (BSD-3-Clause). With hoa/exception removed there is one fewer transitive dependency to carry, so copying Xcallable and the feature-detection helpers into app/Support under your own namespace removes the abandoned dependency entirely and lets you modernize for PHP 8.3+.

Since the archived repo has no CI covering current PHP versions, treat the rewritten doctests as documentation rather than as proof of compatibility. Run your own smoke test on the PHP version your app actually deploys.

Debugging tip. When a callable behaves unexpectedly, log (new Xcallable($callback))->getValidName() before invocation. It quickly distinguishes closures, method arrays, invokable objects, and string callables, which is often the source of container or event-listener misconfiguration.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib