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

Class Info Laravel Package

crodas/class-info

crodas/class-info is a lightweight PHP introspection utility for reading class metadata via reflection. It exposes methods, properties, parent classes, interfaces, and docblocks, making it useful for documentation generation and runtime tooling that needs structured class information.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and confirm the API surface for the tagged version you pulled — the README is thin, so src/ is the real documentation.

composer require crodas/class-info

The package answers one question: what symbols does this PHP file declare? It does that by tokenizing the source (token_get_all) and never include-ing the file, so it is safe to point at untrusted or side-effect-heavy code such as vendor/.

Typical first use:

require __DIR__ . '/vendor/autoload.php';

$info = new ClassInfo\ClassInfo(__DIR__ . '/app/Support/helpers.php');

var_dump($info->getClasses());   // ['App\Support\Foo', ...]
var_dump($info->getFunctions()); // ['app_helper', ...]

If your tag exposes the helpers statically (ClassInfo::getClasses($file)), the result shape is the same — an array of fully-qualified names as written in the file, namespaces resolved, no autoloading performed.

Where to look first:

  1. README.md for the constructor signature.
  2. src/ClassInfo.php (or the single class file) for the exact getter names — expect getClasses(), getFunctions(), and possibly getInterfaces() / getTraits().
  3. tests/ for edge cases the author actually supports (namespaces, conditional declarations, anonymous classes).

First real use case in a Laravel app: build a class => file map over app/ so you can register plugins, discover Artisan commands, or write a lint rule asserting one class per file.

$map = [];
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(app_path()));
foreach ($it as $file) {
    if ($file->getExtension() !== 'php') continue;
    $info = new ClassInfo\ClassInfo($file->getPathname());
    foreach ($info->getClasses() as $class) {
        $map[$class] = $file->getPathname();
    }
}

Implementation Patterns

Cache the scan, key on mtime. Tokenizing a few thousand files on every request is the fastest way to make this package look slow. Persist the map to storage/app/classmap.json and only re-parse files whose filemtime() moved.

$cache = Cache::rememberForever('classmap', fn () => buildClassmap(app_path()));
// invalidate on deploy, or diff mtimes per file

Two-pass discovery: ClassInfo then Reflection. Use ClassInfo only to find names cheaply, then load metadata with new ReflectionClass($fqcn) for parents, interfaces, and attributes. Doing it the other way around means autoloading every file in the tree just to ask what's in it.

Convention linting in CI. A one-liner per file — count($info->getClasses()) === 1 — catches the "two classes in one file" mistake that silently breaks PSR-4 autoloading. Wire it into a Pest test rather than a custom Artisan command; it's ten lines and runs everywhere.

Procedural helper discovery. Laravel projects accumulate app/Support/helpers.php files. Use getFunctions() to register a map of function => file so a require only happens when the helper is actually called, or to assert that every helper is namespaced.

Plugin / module registration. Combine with a directory convention: scan app/Plugins/*/Plugin.php, read getClasses(), filter by an interface you check via Reflection, and register the survivors in a service provider. This avoids enumerating plugin classes by hand.

Fixture-driven development. Because behavior around traits, enums, anonymous classes, and multiple namespaces per file is version-dependent, keep a tests/fixtures/ folder with one pathological file per feature and assert the exact arrays. That fixture suite becomes the spec the README lacks.

Pair with Composer's ClassMapGenerator when you need standards compliance. Composer's --optimize-autoloader already produces a classmap and handles PSR-4 edge cases. Reach for ClassInfo when you need functions too, or when you want the map without a Composer run.

Gotchas and Tips

  • It parses, it does not execute. A class declared inside if (!class_exists(...)) will be reported even when it is never defined at runtime. Treat the output as "candidate symbols", not "loaded symbols".
  • No class_alias, no eval, no dynamic definitions. Anything created at runtime is invisible. Same for classes generated into strings.
  • Enums and PHP 8 syntax. Older releases predate T_ENUM and attributes. Verify with a fixture before trusting getClasses() on a PHP 8.1+ codebase; if enums are missed, either pin the scan to class-like files or fork the token loop (it's short).
  • Traits and interfaces may not appear in getClasses(). Some versions return only T_CLASS. If you need them, call the dedicated getter or scan for T_INTERFACE / T_TRAIT yourself.
  • Unreadable file looks like an empty file. Many versions return [] rather than throwing. Check is_readable() yourself or you'll silently drop classes from the map.
  • Case sensitivity. PHP class names are case-insensitive; array keys are not. Normalize with strtolower() when the map is only used for lookup, but keep the original casing for Reflection.
  • Multiple namespaces or bracketed namespace syntax in one file is where naive tokenizers break. Add a fixture.
  • Duplicates. Conditional polyfills and copy-pasted classes yield the same FQCN from two paths. Detect collisions and fail loudly — that's usually a real bug you want surfaced.
  • No use-statement resolution. You get the FQCN of the declaration, not the parent class or imported names. That's Reflection's job.
  • Version rot. With five stars and no dependents, expect PHP 8 deprecations in the composer.json constraints. If it fights your platform, the whole feature is roughly 80 lines of token_get_all — fork it, or swap to nikic/php-parser if you later need real AST work.
  • Extension point: if the class exposes its token stream, subclass and override the visitor rather than post-processing the returned arrays; it's cleaner than string-matching names afterward.
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.
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
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator