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

Reflection File Laravel Package

rikudou/reflection-file

A PHP library that adds file-level reflection, making it easy to inspect classes, interfaces, traits, functions, and constants declared in a source file. Useful for tooling, static analysis, and package discovery without manually requiring files.

View on GitHub
Deep Wiki
Context7

Getting Started

rikudou/reflection-file is a micro-package that lets you inspect a PHP file and pull out class-level metadata (namespace, class name, use statements) without autoloading or require-ing the file. That is the whole point — it gives you ReflectionClass-style information about classes that don't exist in the runtime yet, or that you don't want to load just to discover.

v1.0.0 has landed, and it shipped with empty release notes. Treat that as the first task: the package was dormant for years at 0.x, so a 1.0.0 bump is simultaneously good news (semver contract going forward, likely a PHP-version refresh) and a risk (the 0.x → 1.0 jump is exactly where breaking changes hide). Before you write any call sites, spend five minutes on the tag diff on GitHub — src/ is a handful of classes, so the whole delta is readable in one sitting. Pay attention to changed method names, new return types, and any new constructor arguments.

Install, then verify:

composer require rikudou/reflection-file
php -r 'require "vendor/autoload.php"; var_dump((new Rikudou\ReflectionFile\ReflectionFile(__FILE__))->getClassName());'

That one-liner catches the two failure modes that matter: a signature change you didn't notice, and a PHP-version incompatibility. Then read vendor/rikudou/reflection-file/src/ end to end — you're not integrating a framework, you're calling one object.

A minimal first use case in a Laravel app — discovering every class in a directory without loading them:

use Rikudou\ReflectionFile\ReflectionFile;
use Symfony\Component\Finder\Finder;

$classes = [];

foreach (Finder::create()->files()->in(app_path('Services'))->name('*.php') as $file) {
    $reflection = new ReflectionFile($file->getRealPath());

    if ($reflection->getClassName() !== null) {
        $classes[] = $reflection->getNamespaceName() . '\\' . $reflection->getClassName();
    }
}

This is the kind of job Laravel's own Illuminate\Support\ClassLoader-adjacent helpers, Symfony's ClassMapGenerator, and spatie/laravel-package-tools typically handle — so evaluate whether you actually need this package versus rolling a 10-line token_get_all helper.

Implementation Patterns

Auto-discovery in a service provider. The natural Laravel fit is dynamic binding / registration inside register(), where you want to scan a directory of implementations and bind them by convention:

public function register(): void
{
    foreach (Finder::create()->files()->in(app_path('Contracts/Implementations')) as $file) {
        $ref = new ReflectionFile($file->getPathname());
        $fqcn = $ref->getNamespaceName() . '\\' . $ref->getClassName();

        if (is_subclass_of($fqcn, MyContract::class)) {
            $this->app->bind(MyContract::class, $fqcn);
        }
    }
}

Building a class map for a package. When you ship a package with a src/ tree and want a manifest of FQCNs for config merging, command registration, or a generated providers.php, iterate once at build time and cache the result. Combine with php artisan config:cache-style caching so you never call this in a hot request path.

Filtering by use statements before loading. Because you can read imports without autoloading, you can skip files that clearly can't be relevant (e.g. only load classes whose use list references a specific attribute or interface):

$ref = new ReflectionFile($path);
if (! in_array(SomeAttribute::class, $ref->getUseStatements(), true)) {
    continue;
}

This is useful for attribute-based discovery on large codebases where autoloading every class to run ReflectionClass::getAttributes() is too expensive. Confirm getUseStatements() survived v1.0.0 unchanged — it's the most likely candidate for a rename or a return-shape change in a major bump.

Companion to a custom console command. A php artisan app:discover command that walks app/, extracts FQCNs, and writes a cache file is the cleanest encapsulation — keep the reflection work in the command, not in a provider that runs on every request.

Gotchas and Tips

  • v1.0.0 shipped with no release notes. You have a version number and nothing else. Diff the tags, read composer.json for the new php constraint, and run the smoke test above. Also check whether the license changed — a major release is the usual moment for that to happen.
  • You may not even have upgraded. If your composer.json pins ^0.x (likely, given the package's age), composer require won't jump you to 1.0.0 — you'll stay on the old tag and get none of the fixes. Check with composer show rikudou/reflection-file and bump the constraint deliberately, in a PR, so the diff is reviewable.
  • Pin to ^1.0, not *. A package that wakes up after six years of dormancy often gets a 1.0.1/1.0.2 flurry in the following weeks. A caret constraint gets you the bugfixes without letting a surprise 2.0 in.
  • It does not autoload and does not resolve aliases. getUseStatements() returns the literal use targets — it won't expand use Foo as Bar; into Bar → Foo\Bar for you. Do that mapping yourself if you need FQCN resolution.
  • Zero dependents, zero stars. There is effectively no community to lean on for bugs. Treat the class as a small body of code you now own; if the API surface you need is tiny, vendoring it into a helper is still a legitimate exit.
  • WTFPL license. Permissive to the point of being non-standard. Many corporate legal/compliance scanners will flag or reject it. If your org has a license allow-list, confirm WTFPL is on it before adding a dependency — for one class, copying the logic may be less friction than the dependency review.
  • Files with multiple classes or no class. getClassName() will be null for a file containing only functions, interfaces, or traits (depending on what the implementation parses). Always null-check before concatenating the FQCN, or you'll get Namespace\ strings that blow up is_subclass_of().
  • Conditional class declarations. if (! class_exists(...)) { class Foo {} } — tokenizer-based parsers see the class block regardless of runtime condition. Don't trust the output as a guarantee the class is loadable.
  • Don't call it in a request hot path. File I/O plus tokenization per request adds up. Cache the extracted map (Cache::rememberForever, or written to bootstrap/cache/) and invalidate on deploy.
  • Debugging tip: if you get surprising output, dd(token_get_all(file_get_contents($path))) against the same file — you're almost always looking at a parsing edge case (heredoc containing class, PHP 8 attributes above the class, enums, readonly classes) rather than a bug in your call site. If v1.0.0 was a PHP 8 modernization pass, these edge cases are precisely what to re-test.
  • Extension points are minimal. Since this is a single class with a file-path constructor, the practical way to "extend" it is to wrap it in your own ClassDiscoverer service and swap the underlying implementation later — which is exactly why you should keep it behind an interface so you can drop it for symfony/finder + token_get_all without touching callers. That advice is more relevant now, not less: a major version bump is the cheapest possible moment to decide you'd rather not depend on someone else's parser.
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.
teamzac/geocoder
ideatica/config-writer
keaton-php/pipe-dream
jacksonwebservices/laravel-user-suite
maksimru/conditional-laravel-debugbar
gismatul/nova-support-chat
gismatul/laravel-support-chat
networkrailbusinesssystems/oracle-api
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel