sajadsdi/php-reflection
Lightweight wrapper around PHP’s built-in Reflection API. Inspect classes by name or instance and quickly fetch ReflectionClass plus lists of properties, methods, and constants. Simple Reflections helper for common reflection tasks.
Installation:
composer require sajadsdi/php-reflection
Ensure your project uses PHP 8.1+ (as per composer.json).
First Use Case: Inspect a class's structure (e.g., methods, properties) without manually reading its code.
use Sajadsdi\PhpReflection\Reflections;
$reflector = new Reflections();
$methods = $reflector->methods(\App\Models\User::class);
Where to Look First:
Reflections class: Core entry point for all reflection operations.Reflections::getInstance() for performance-critical scenarios (e.g., repeated calls in a loop).Dynamic Class Inspection:
$reflector = new Reflections();
$properties = $reflector->properties(\App\DTO\RequestDTO::class);
foreach ($properties as $property) {
echo "Property: {$property->getName()}, Type: " . ($property->hasType() ? $property->getType()->getName() : 'mixed') . "\n";
}
Integration with Laravel:
$rules = [];
foreach ($reflector->properties(\App\Models\Post::class) as $property) {
$rules[$property->getName()] = 'required|string';
}
return $rules;
$method = $reflector->reflection(\App\Policies\PostPolicy::class)->getMethod('view');
if ($method && $method->isPublic()) {
// Grant access
}
Performance Optimization:
$cacheKey = 'reflection:App\Models\User';
$reflection = cache()->remember($cacheKey, now()->addHours(1), function () use ($reflector) {
return $reflector->reflection(\App\Models\User::class);
});
Event Listeners/Service Providers:
Reflections instance in a service provider's boot() method for global access.
public function boot()
{
$this->app->singleton(Reflections::class, function () {
return new Reflections();
});
}
Testing:
public function testUserModelHasEmailProperty()
{
$reflector = new Reflections();
$property = $reflector->reflection(\App\Models\User::class)->getProperty('email');
$this->assertTrue($property->isInitialized());
}
Singleton Overhead:
// Avoid:
$reflector = new Reflections();
// Prefer:
$reflector = app(Reflections::class);
Reflection Limitations:
ReflectionClass, so it inherits limitations (e.g., private/protected members require ReflectionClass::newInstanceWithoutConstructor()).ReflectionClass directly for advanced use cases:
$reflection = new \ReflectionClass(\App\Models\User::class);
$privateProp = $reflection->getProperty('secret');
$privateProp->setAccessible(true);
PHP 8.1+ Only:
nikic/php-parser for reflection-like functionality.Circular Dependencies:
A references B, which references A) may cause stack overflows.try {
$reflector->reflection(CircularClass::class);
} catch (\ReflectionException $e) {
// Fallback logic
}
Performance with Large Classes:
$reflector->methods(\App\Models\LargeModel::class, true); // Lazy loading (if supported)
Verify Class Existence:
if (!class_exists(\App\Models\User::class)) {
throw new \RuntimeException('Class not found');
}
Check for Typos:
getMethod() or getProperty() to validate existence:$method = $reflector->reflection(\App\Services\Logger::class)->getMethod('log');
if (!$method) {
throw new \InvalidArgumentException('Method not found');
}
Enable Reflection Exceptions:
ini_set('reflection.emitExceptions', 1);
Custom Reflection Helpers:
Reflections class to add domain-specific methods:class ExtendedReflections extends Reflections {
public function getTableName(string $class): string
{
$reflection = $this->reflection($class);
return $reflection->getConstant('TABLE_NAME') ?? strtolower(class_basename($class));
}
}
Integration with Laravel Scout:
public function toSearchableArray()
{
$reflector = new Reflections();
$searchable = [];
foreach ($reflector->properties(self::class) as $property) {
if ($property->getName() !== 'created_at') {
$searchable[$property->getName()] = $property->getValue($this);
}
}
return $searchable;
}
Event-Based Reflection:
event(new \App\Events\ReflectionUpdated(
\App\Models\Post::class,
$reflector->methods(\App\Models\Post::class)
));
Mocking in Tests:
ReflectionClass::newInstanceWithoutConstructor() to mock private constructors:$reflection = new \ReflectionClass(\App\Services\PaymentGateway::class);
$instance = $reflection->newInstanceWithoutConstructor();
$instance->setTestMode(true);
How can I help you explore Laravel packages today?