Ir al contenido principal

PHP: Reflection para acceder a propiedades protected desde afuera

The protected access modifier in PHP restricts visibility of class properties and methods to within the defining class and its subclasses (child classes), while preventing access from external code.  This modifier is essential for encapsulation and inheritance control, allowing parent classes to expose internal logic or data to derived classes without exposing it to the general application scope. 

Key characteristics include:

  • Subclass Access: Child classes can directly access and modify protected members using $this

  • External Restriction: Instantiated objects of the class or its subclasses cannot access protected members directly from outside the class hierarchy. 

  • Default Behavior: If no access modifier is specified, class members are treated as public

  • Inheritance: Protected members remain protected in child classes and are inherited, unlike private members which are not accessible by subclasses. 

class ParentClass {
    protected $value = "Protected";

    protected function getProtectedValue() {
        return $this->value;
    }
}

class ChildClass extends ParentClass {
    public function display() {
        // Allowed: Accessing protected member in subclass
        return $this->getProtectedValue(); 
    }
}

$obj = new ChildClass();
echo $obj->display(); // Output: Protected
// echo $obj->value;   // Error: Cannot access protected property
Is there a package access scope like in Java (activated when no access specifier is given)?

No. PHP has no package-private (or "namespace-private") access modifier.  When no access specifier is given, the default is public — for backward compatibility with PHP 4, which had no visibility keywords at all. 

LanguageDefault (no modifier)Package-level scope?
Javapackage-private✅ yes
PHPpublic❌ no

Why it was never added

A PHP RFC for "Namespace Visibility" was proposed, which would have allowed public, protected, and private keywords on classes/interfaces/traits scoped to a namespace. It was rejected primarily because making the default anything other than public would have been a massive backwards-incompatibility. 

Common workarounds

  • Anonymous classes — used to simulate "package-private" classes that can't be instantiated from outside the library (but can still be accessed via their public API). 

  • Convention — simply prefix "internal" classes with @internal in docblocks and treat them as private by convention (this is what many frameworks like Symfony and Laravel do).

  • final + private constructor — to restrict instantiation patterns, though this doesn't truly hide the class.

In short, PHP's visibility model is strictly class-based (public / protected / private) with no namespace-level scope. 


Laravel: How does Eloquent find the casts attribute as it's protected? And likewise, how can Artisan find the Command's signature property as it's protected?


Laravel uses PHP Reflection and magic methods to access protected properties like $casts or a Command's $signature

1. Eloquent Attribute Casting

The Eloquent Model class uses the HasAttributes trait.  When you access a model attribute (e.g., $model->is_admin), the __get magic method intercepts the call. This method checks the casts property (which can be a protected $casts array or a protected casts() method) to determine if the raw database value needs to be transformed (e.g., casting a JSON string to an array).  The framework uses reflection to read the protected $casts array if the casts() method is not defined, or merges both sources. 

2. Artisan Command Signature

Similarly, the Artisan Command class uses the ReflectsCommand trait or internal reflection logic. When the Artisan console parses the command, it uses PHP's ReflectionClass to inspect the command instance. Reflection allows Laravel to read the values of protected properties like $signature or $description without needing public getters, as reflection bypasses standard PHP visibility restrictions (protected/private) for inspection purposes.

Key Mechanism:

  • Magic Methods (__get): Intercept attribute access in Eloquent.

  • PHP Reflection (ReflectionClass): Allows Laravel to read protected properties directly during runtime inspection for both Eloquent casts and Artisan command metadata. 

Comentarios