ucscode/object-reflector

A reflector that provides access to class encapsulated properties or methods

1.0.0 2025-05-04 05:48 UTC

This package is auto-updated.

Last update: 2025-05-04 05:52:53 UTC


README

ObjectReflector is a lightweight PHP utility that uses reflection to access private and protected properties and methods of any object. It’s especially useful in testing, debugging, or meta-programming scenarios where encapsulation boundaries need to be temporarily bypassed. It also allows controlled access to internal logic where needed — particularly when internal state updates must be possible, but not easily exposed to external misuse.

🚀 Installation

Install via Composer:

composer require ucscode/object-reflector

Why Access Private Properties and Methods?

Reason 1:

In an ideal world, you wouldn't need to touch private or protected members of an object. But in reality, there are valid use cases:

  • Unit Testing internal logic or state without exposing implementation
  • Debugging complex objects from third-party libraries
  • Framework or tooling development (e.g., mocking or snapshotting internals)
  • One-off migration scripts where deep access is required

Rather than making properties public just to test them, use reflection in a clean, reusable, and controlled way.

Reason 2:

You may need to modify or invoke private/internal properties and methods without exposing public setters that invite accidental misuse.

Real-world scenario

Suppose you have:

class Config {
    private string $path;

    public function getPath(): string {
        return $this->path;
    }

    public function setPath(string $path): void {
        $this->path = $path;
    }
}

Now imagine that once the path is set internally, you don't want any external code to modify it again. This is tricky in PHP because its visibility model doesn’t fully support one-time, internal-only mutability.

You have a few imperfect options:

  1. Readonly property

    • Available in PHP 8.1+
    • Only works at construction time (__construct)
    • Doesn't allow deferred mutation from within the same or related services
    • Cannot work if the $path must be set externally after a complex computation
  2. Throw an exception in setPath()

    • Adds state-checking logic
    • Can be bypassed unless every access point follows the rule
    • Still exposes a public setter to all callers
    • Can be overridden by child classes
  3. Use internal flags or context-aware guards

    • Adds more code complexity
    • Easy to misuse or forget in future updates

The Better Approach: Controlled Reflection

Instead of exposing risky public mutators, you can keep the method private and use ObjectReflector to set it intentionally:

class Config {
    private string $path;

    public function getPath(): string {
        return $this->path;
    }

    private function setPath(string $path): void {
        $this->path = $path;
    }
}
$reflector = new ObjectReflector($config);
$reflector->invokeMethod('setPath', '/secure/location');

Why This Works

  • You're keeping the setPath() logic encapsulated and unavailable to external callers.
  • You're enforcing immutability by hiding the method rather than exposing and policing it.
  • Any developer trying to change the path later must consciously bypass encapsulation using reflection — this is no longer a mistake, it's a deliberate override.

This strikes a clean balance between flexibility and safety: the class can still mutate its state in special, controlled contexts — without accidentally giving the entire app that power.

Usage

use Ucscode\ObjectReflector\ObjectReflector;

$reflector = new ObjectReflector($object);

getProperty(string $name): mixed

Access a private or protected property.

$value = $reflector->getProperty('token');

setProperty(string $name, mixed $value): void

Set a private or protected property.

$reflector->setProperty('token', 'new-value');

invokeMethod(string $name, mixed ...$args): mixed

Invoke a private or protected method with standard arguments.

$result = $reflector->invokeMethod('compute', 42);

invokeMethodArray(string $name, array $args): mixed

Invoke a private or protected method using an array of arguments.

$result = $reflector->invokeMethodArray('compute', [42]);

Example

class SecureSettings {
    private string $token = 'abc-token';

    public function getToken(): string {
        return $this->token;
    }
}

$settings = new SecureSettings();
$reflector = new ObjectReflector($settings);

// Set a private property directly
$reflector->setProperty('token', 'xyz-token');

echo $settings->getToken(); // xyz-token

License

MIT — free to use, modify, and distribute.