veewee/reflecta
Reflecta is a PHP library for fast, reflection-based class inspection, letting you read properties, methods, and attributes without instantiating objects. Useful for building analyzers, mappers, and framework tooling.
composer require veewee/reflecta. The current release line is 1.2.x (1.2.0 added property_is_initialized), so pin ^1.2 if you intend to use the new helper. Confirm PHP 8+ and that your autoloader is configured. Start with src/ and tests/ — the test suite is the most reliable documentation.ReflectionClass — and use the tests as executable documentation. Note that 1.2.0's small, additive changelog (one PR, no BC breaks advertised) suggests the API is still settling; read the diff of any version bump before upgrading.$class = Reflect::class(MyService::class); // illustrative; check actual API
$routeAttributes = $class->attributes(Route::class);
$publicMethods = $class->methods()->public();
foreach ($publicMethods as $method) {
foreach ($method->parameters() as $parameter) {
// inspect parameter type, attributes, defaults
}
}
#[Route], #[Validate], or #[Serialize], and register the results in a container, router, validator, or schema generator. This plays directly to Reflecta's strengths: attribute inspection, fluent navigation, and type-safe wrappers.property_is_initialized: a hydration/serialization inspector that reports which typed properties on a given object actually hold a value — useful for DTO mappers, snapshot diffs, and "lazy relation loaded?" checks.ReflectionClass/ReflectionMethod available for edge cases the wrapper does not cover. If Reflecta becomes central, hide it behind a small internal adapter so you can swap or upgrade it later.class => metadata, and defer newInstance() calls until you actually need the attribute object. This is the main day-to-day pattern for routing, validation, serialization, DI compilation, and documentation generation.getValue() on a typed property, check initialization via the new helper (native equivalent: ReflectionProperty::isInitialized()); naming in the wrapper may be isInitialized() or similar — confirm in tests/. Wrap this in a small helper so call sites read intentionally:foreach ($reflector->properties() as $property) {
$value = $property->property_is_initialized($instance) // illustrative name
? $property->value($instance)
: null; // or a domain-specific "unset" sentinel
}
null, an omitted key, or a dedicated Uninitialized marker. Serializers that conflate the two produce subtly wrong payloads (e.g. PATCH semantics).self, static, never, and enum types.findRouteAttributes(), publicMethodNames(), constructorParameterTypes() — rather than modifying package internals. A one-PR release like 1.2.0 is a good reminder that upstream moves on its own schedule.composer.json, read the tests before relying on a method, and wrap the package behind an internal interface if it becomes central to your application.getValue() on a typed property that was never assigned raises Error: Typed property ... must not be accessed before initialization. In 1.2.0 you can now guard this with property_is_initialized; before that you had to catch the error or pre-check with native reflection. Always guard, never try/catch (\Error) around a loop.isInitialized() takes the object under inspection; static properties behave differently (no instance required / instance ignored). Confirm how the wrapper models this and test on the PHP versions you deploy — semantics have shifted across PHP 8.x minors.isInitialized() is not isset(). A property explicitly set to null is initialized. If your logic uses isset() today, switching to the new helper can change behavior for nullable properties. Decide intentionally.newInstance() on an attribute runs its constructor. Inspect metadata first and instantiate only when safe. Attribute classes must be autoloadable; a missing attribute class can throw during scanning.never, static, self, parent, enums, readonly properties, and internal classes can behave differently across PHP versions. Test on the PHP versions you deploy and compare Reflecta's normalized output with native getType() when debugging.ReflectionClass where a Reflecta wrapper is expected, or vice versa, will produce type errors. Keep a clear boundary: native reflection at the edge, Reflecta wrappers in your analysis services.ReflectionClass, ReflectionMethod, getAttributes(), getParameters(), getType(), and isInitialized() for the same target. This quickly isolates whether the issue is your traversal or the wrapper.How can I help you explore Laravel packages today?