Cómo obtener la propiedad protegida de un objeto en PHP

Resuelto Awais Qarni asked hace 54 años • 8 respuestas

Tengo un objeto que tiene alguna propiedad protegida que quiero obtener y configurar. El objeto parece

Fields_Form_Element_Location Object
(
[helper] => formText
[_allowEmpty:protected] => 1
[_autoInsertNotEmptyValidator:protected] => 1
[_belongsTo:protected] => 


[_description:protected] => 
[_disableLoadDefaultDecorators:protected] => 
[_errorMessages:protected] => Array
    (
    )

[_errors:protected] => Array
    (
    )
[_isErrorForced:protected] => 
[_label:protected] => Current City


[_value:protected] => 93399
[class] => field_container field_19 option_1 parent_1
)

Quiero obtener valuela propiedad del objeto. Cuando lo intento $obj->_valueo $obj->valuegenera error. Busqué y encontré la solución a utilizar PHP Reflection Class. Funcionó en mi versión local pero en el servidor PHP, 5.2.17por lo que no puedo usar esta función allí. Entonces, ¿alguna solución para obtener dicha propiedad?

Awais Qarni avatar Jan 01 '70 08:01 Awais Qarni
Aceptado

Aquí está el ejemplo realmente simple (sin verificación de errores) de cómo usarlo ReflectionClass:

function accessProtected($obj, $prop) {
  $reflection = new ReflectionClass($obj);
  $property = $reflection->getProperty($prop);
  $property->setAccessible(true);
  return $property->getValue($obj);
}

Sé que dijiste que estabas limitado a 5.2, pero eso fue hace 2 años, 5.5 es la versión más antigua compatible y espero ayudar a las personas con las versiones modernas.

drewish avatar Feb 05 '2015 19:02 drewish

El objeto se puede encasillar en una matriz (asociativa) y los miembros protegidos tienen claves con el prefijo chr(0).'*'.chr(0)(consulte el comentario de @fardelian aquí ). Usando esta característica no documentada puedes escribir un "expositor":

function getProtectedValue($obj, $name) {
  $array = (array)$obj;
  $prefix = chr(0).'*'.chr(0);
  return $array[$prefix.$name];
}

Alternativamente, puede analizar el valor de una cadena serializada , donde (parece) los miembros protegidos tienen el mismo prefijo.

Esto funciona en PHP 5.2 sin la sobrecarga de ReflectionClass. Sin embargo, existen razones por las que algunas propiedades están protegidas y ocultas del código del cliente. La lectura o escritura puede hacer que los datos sean inconsistentes o el autor proporciona alguna otra forma de exponerlos en un esfuerzo por hacer que la interfaz sea lo más sencilla posible. Cuando hay motivos para leer la propiedad protegida directamente, el enfoque correcto era implementar el método mágico __get() , así que siempre verifique si hay alguno y vea qué hace. Esta búsqueda contraria a la intuición finalmente se resolvió en PHP 8.1 con propiedades de sólo lectura .

Desde PHP 8.0, también hay metadatos de atributos a los que puede acceder ReflectionClass; asegúrese de verificarlos también antes de intentar ingresar a miembros protegidos. Los atributos reemplazaron a las "Anotaciones" 1 , así que revíselos también.

1: las anotaciones son una sorpresa muy desagradable para los codificadores de los clientes: analizan los comentarios para agregar una funcionalidad confusa, inútil y extravagante, que ya no debería usarse, pero aún existen.

Jan Turoň avatar Jan 03 '2015 11:01 Jan Turoň

Para eso sirve "protegido", como explica el capítulo Visibilidad :

Solo se puede acceder a los miembros declarados protegidos dentro de la propia clase y mediante clases heredadas y principales.

Si necesita acceder a la propiedad desde el exterior, elija uno:

  • No lo declares como protegido, hazlo público
  • Escriba un par de funciones para obtener y establecer el valor (captadores y definidores)

Si no desea modificar la clase original (porque es una biblioteca de terceros que no desea alterar), cree una clase personalizada que extienda la original:

class MyFields_Form_Element_Location extends Fields_Form_Element_Location{
}

... y agregue su captador/definidor allí.

Álvaro González avatar Dec 02 '2013 17:12 Álvaro González

Si quieres jugar con una clase sin agregar captadores y definidores....

PHP 7 agrega un método call($obj) (más rápido que el antiguo bindTo) en los cierres, lo que le permite llamar a una función para que la $thisvariable actúe tal como lo haría dentro de una clase, con permisos completos.

 //test class with restricted properties
 class test{
    protected $bar="protected bar";
    private $foo="private foo";
    public function printProperties(){
        echo $this->bar."::".$this->foo;   
     }
 }

$testInstance=new test();
//we can change or read the restricted properties by doing this...
$change=function(){
    $this->bar="I changed bar";
    $this->foo="I changed foo";
};
$change->call($testInstance);
$testInstance->printProperties();
//outputs I changed bar::I changed foo in php 7.0 
user2782001 avatar Jun 05 '2017 04:06 user2782001