typhoon/declaration-id
Generate stable, unique IDs for PHP declarations (classes, functions, methods, properties) to track and reference code elements across analyses and tooling. Lightweight package with strict typing and static-analysis-friendly design.
Installation:
composer require typhoon/declaration-id
Ensure your project uses PHP 8.1+ (required by the package).
First Use Case: Generate a unique ID for a Laravel service class:
use Typhoon\DeclarationId\DeclarationId;
$id = DeclarationId::of(\App\Services\UserService::class);
// Output: e.g., "a1b2c3d4e5" (a stable hash for the class)
Where to Look First:
DeclarationId::of() for classes, functions, and constants.php vendor/bin/phpunit to verify the package’s core functionality.Replace hardcoded binding strings with generated IDs:
// Traditional binding
$this->app->bind('user_service', \App\Services\UserService::class);
// With DeclarationId
$this->app->bind(
DeclarationId::of(\App\Services\UserService::class),
\App\Services\UserService::class
);
Use IDs to register macros dynamically:
$id = DeclarationId::of(\Illuminate\Support\Str::class);
\Illuminate\Support\Str::macro($id, function () {
return 'Dynamic macro for Str';
});
Generate stable IDs for event classes:
$eventId = DeclarationId::of(\App\Events\UserRegistered::class);
event(new UserRegistered());
// Later, resolve the event by its ID (if needed).
Create a helper to generate IDs for views:
function bladeTemplateId(string $view): string {
return DeclarationId::of(\Illuminate\View\View::make($view));
}
Use in Blade:
@inject('templateId', 'bladeTemplateId', ['view' => 'dashboard'])
Resolve services by ID in constructors:
class UserController {
public function __construct(
private readonly string $userServiceId
) {
$this->userServiceId = DeclarationId::of(\App\Services\UserService::class);
}
}
Cache IDs: Store generated IDs in app() or a static cache to avoid recomputation:
$cache = app()->make('cache');
$id = $cache->remember(
"declaration_id:{$class}",
now()->addHours(1),
fn() => DeclarationId::of($class)
);
Laravel Service Provider: Register a helper class to centralize ID generation:
$this->app->singleton('declaration-id', function () {
return new class {
public function generate(string $class): string {
return DeclarationId::of($class);
}
};
});
Testing: Mock IDs in unit tests to avoid flakiness:
$mockId = 'test_user_service';
DeclarationId::shouldReceive('of')
->with(\App\Services\UserService::class)
->andReturn($mockId);
Namespace Sensitivity:
IDs are namespace-sensitive. A class App\User and Vendor\User will generate different IDs.
\App\Services\UserService).Anonymous Classes: Anonymous classes may produce unpredictable IDs.
PHP 8.1+ Requirement: The package will not work on PHP 8.0 or lower.
ID Collisions: While rare, collisions can occur with custom naming strategies.
DeclarationId::of($class) . '_service').Blade Template Limitations:
Blade components (e.g., @component) may not generate stable IDs.
Log Generated IDs: Add a debug method to log IDs during development:
DeclarationId::debug(\App\Services\UserService::class);
// Output: "UserService => a1b2c3d4e5"
Validate IDs: Ensure IDs are consistent across requests:
$id1 = DeclarationId::of(\App\Services\UserService::class);
$id2 = DeclarationId::of(\App\Services\UserService::class);
assert($id1 === $id2, 'ID generation is not deterministic!');
Check for Typos: Typos in class names will produce unexpected IDs. Use IDE autocompletion to verify.
No Built-in Laravel Hooks:
The package has no Laravel-specific configuration. You must manually integrate it (e.g., in AppServiceProvider).
Custom Naming Strategies: The default hash may not suit all use cases. Extend the package:
class CustomDeclarationId {
public static function of(string $class): string {
return strtolower(str_replace('\\', '.', $class));
}
}
Support for Templates: Extend to handle Blade templates or custom view logic:
DeclarationId::extend('blade', function ($view) {
return DeclarationId::of(\Illuminate\View\View::make($view));
});
Integration with Typhoon Framework: If using Typhoon, leverage its DI container for seamless ID resolution:
use Typhoon\DependencyInjection\Container;
$container->bind(
DeclarationId::of(\App\Services\UserService::class),
\App\Services\UserService::class
);
Performance Optimization:
Precompute IDs during class registration (e.g., in a BootstrapServiceProvider):
$this->app->when(\App\Services\UserService::class)
->needs('$id')
->give(DeclarationId::of(\App\Services\UserService::class));
Fallback for Unsupported Declarations: Handle edge cases (e.g., anonymous functions) with a fallback:
$id = DeclarationId::of($anonymousFunction) ?? 'anonymous_' . uniqid();
How can I help you explore Laravel packages today?