nette/robot-loader
RobotLoader automatically loads PHP classes, interfaces, and traits from specified directories by scanning files and caching the results. It spares you from manually requiring or registering each class, making it handy for legacy code or small projects without Composer.
Build vs. buy for runtime class discovery. The recurring question is "find every class in this tree that implements X, or lives in this folder we don't control at build time." RobotLoader is the bought answer: tokenizer scan, path resolution, persistent index, atomic cache writes, lazy rebuild. Prototyping that is a day; making it correct across Windows renames, concurrent workers, PHAR paths, and every PHP minor is a quarter. Adopting it deletes a maintenance line item and a class of subtle bugs we would otherwise own.
Roadmap: plugin / extension / module surface. This is the only decision where the package is strategically load-bearing. Laravel's package auto-discovery (bootstrap/cache/packages.php) only sees Composer packages. If the roadmap includes customer- or partner-supplied modules that are dropped into a directory rather than composer required — tenant-specific modules, marketplace plugins, white-label extensions — RobotLoader is the discovery primitive that unlocks that feature class. Without it, the feature either doesn't ship or ships as a bespoke scanner.
Use cases worth sizing, in Laravel terms: auto-registering discovered EventServiceProvider-style subscribers, console commands, or Illuminate\Contracts implementations into the container without touching config/app.php; generating a manifest of available integrations for an admin UI; scanning generated/scaffolded code in build tooling where a ParseError should surface as a diagnostic instead of a fatal.
Explicitly not an autoloader swap. Any proposal framed as "replace Composer's autoloader" should be rejected at the PM level. Composer PSR-4 plus dump-autoload -o is load-bearing in every Laravel deploy, and swapping it is high-risk with zero user-visible benefit. Scope the decision to a second, narrowly bounded discovery mechanism.
Support-matrix input. v4.x requires PHP 8.1. Laravel 10/11/12 are fine; if any service still runs Laravel 9 on PHP 8.0, adoption forces a pin to 3.4.x or an upgrade commitment. Surface that as a dependency before engineering finds it.
Deprioritizing internal tooling. Teams hand-roll "list all classes implementing this interface" scripts every couple of years. Standardizing on a focused library stops the cycle.
Not a decision the package makes for us: it ships no Laravel service provider. Wrapping it in a singleton binding and a config file is our code, our ownership, our tests.
Adopt when most of these hold:
App\ code, RobotLoader only for the dynamic directories. Blurring that line is where incidents come from.Look elsewhere when:
package:discover is the supported path and needs no addition.symfony/finder plus token_get_all() is a few dozen lines and fully debuggable; prefer it.setCacheDirectory() (formerly setTempDirectory()) is a hard gate, not a tunable. Laravel gives you storage/framework/ and bootstrap/cache/, so this is usually satisfiable, but it must be an absolute path and must exist.NOASSERTION; the Nette ecosystem is typically BSD-3-Clause, but do not sign off on redistribution inside a commercial or SaaS product without legal confirming terms. Checklist item, not a blocker — but not skippable.To executives: "This is a small, actively maintained component that lets us discover code at runtime. It is the enabler for a plugin/extension model where customers or partners add capability without us cutting a release — a revenue-adjacent capability, not plumbing. It is not a rewrite of our autoloading; Composer stays the source of truth and this is scoped to the directories we deliberately keep dynamic. Cost is one dependency plus a cache directory we already have in storage/framework. The release history shows steady PHP-version support and clean static analysis, so ongoing maintenance is close to zero, though it is a niche library with effectively no downstream ecosystem, so we own the integration. Two caveats to acknowledge: legal needs to confirm the license, and this is inappropriate for the large majority of our codebase where Composer already does the job. Recommendation: pilot behind the plugin-discovery use case only."
To engineering: "Treat it as a discovery primitive, not an autoloader swap. Bind one singleton in a service provider, keep configuration centralized (directories, excludes, accepted files, absolute cache directory under storage/framework/ or bootstrap/cache/), and confine it to directories that are genuinely dynamic — never app/. Warm the index in the deploy pipeline with refresh() rather than letting the first production request pay for the rebuild, and make sure the cache directory is absolute, exists, and is writable by the runtime user. Three sharp edges: the mandatory writable cache directory, case-sensitive class lookups since v3.0.0, and the PHP 8.1 floor if anything still ships 8.0. Add a test asserting getClasses() output is stable so a cache regression fails CI instead of production, and re-read docs/ before non-trivial changes since the internals are documented there rather than in the manual."
How can I help you explore Laravel packages today?