Bueno, esto realmente no es que sea algo asombroso, aunque sí cuando menos curioso y en que no sueles caer, pero que es básico en OOP. Lo descubrimos el grupo de estudio durante la preparación para la certificación en PHP, en una de las reuniones que celebramos María Berenguer, Jorge Ferrer, Ricardo Ocaña y un servidor. Durante una de nuestras sesiones de estudio surgió una pregunta en la cual nos planteamos un ejercicio práctico en donde se accedía a métodos y propiedades privadas dentro de objetos de la misma clase.

La verdad es que lo primero que te da por pensar es que no es posible. Cuando pensamos en ámbito private (privado) en Programación Orientada a Objetos consideramos, quizás por la propia connotación en el lenguaje natural de la palabra, que el ámbito de resolución de cualquier método o propiedad definido de tal modo es de objeto. Y no es así.

Y no sólo en PHP, sino en cualquier lenguaje de programación que se base en el paradigma OOP (C++, Java, .NET, PHP, etc) se dan las siguientes definiciones de ámbito. Amén de otros ámbitos posibles, estos son los comunes con PHP.

[list type=»check»]

  • Privado (private). Cuando declaramos una propiedad o método como privado sólo lo podremos acceder desde la propia clase. Este es el más restrictivo y el que se recomienda para los campos y las funciones de uso interno. Lo cual quiere decir que objetos de la misma clase pueden acceder a dichos métodos y propiedades de otros objetos instanciados.
  • Protegido (protected). Uso protegido. Los elementos declarados como protegidos sólo estarán accesibles, además de en la propia clase, por cualquier clase derivada.
  • Público (public). Este modificador de ámbito nos permite exponer públicamente cualquier miembro de la clase, de forma que no haya restricciones para acceder a él.

[/list]

Cuando declaramos una propiedad o método como privado sólo lo podremos acceder desde la propia clase. Lo cual quiere decir que objetos de la misma clase pueden acceder a dichos métodos y propiedades de otros objetos instanciados.

Y para muestra un botón. Definamos un código en el cual vamos a instanciar dos objetos de la misma clase con una propiedad de ámbito privado a ver si es posible modificarla y obtenersu valor desde otro objeto de la misma clase.

Parte 1:

class prueba {   
 
  private $secreto;                // Confirmado. Es privado 
 
  public function __construct ($value)   {     
    $this->secreto = $value;
  }
 
  public function asignaPropiedadSecreta ($otroObjeto)
  {
    $this->secreto = $otroObjeto->;secreto;
  }
 
  public function muestraPropiedadSecreta ()
  {
    echo $this->secreto;
  }
 
}
 
$a = new prueba('a');
$b = new prueba('b');
 
$b->asignaPropiedadSecreta ($a);
$b->muestraPropiedadSecreta ();  // Alucina. Muestra a!!

Imagina que tienes dos perros gemelos y quieres cortar el pelo a uno. Pero de repente te das cuenta que puedes cortarles el pelo al otro gemelo también a través del primero.

Jorge Ferrer

Por supuesto, si añadimos otra clase, aunque sean los mismos métodos no funciona y devuelve un Fatal Error. Añadamos este código.

Parte 2:

class prueba2
{
 
  private $secreto;
 
  public function __construct ($value)
  {
    $this->secreto = $value;
  }
 
  public function asignaPropiedadSecreta ($otroObjeto)
  {
    $this->secreto = $otroObjeto->secreto;
  }
 
  public function muestraPropiedadSecreta ()
  {
    echo $this->secreto;
  } 
 
}
 
$c = new prueba2('c');
$c->asignaPropiedadSecreta ($a); // Fatal error: Cannot access private property prueba::$secreto
$c->muestraPropiedadSecreta ();

Así pues, queda claro que se puede acceder a propiedades y métodos privados dentro de objetos de la misma clase. Pero nos queda algo pendiente. ¿Qué sucede cuando extendemos la clase y utilizamos los métodos y propiedades por herencia? Probemos y sustituyamos el código de la parte 2 por este:

Parte 3:

class prueba3 extends prueba {
 
  private $secreto;
 
  public function __construct ($value)
  {
    $this->secreto = $value;
  }
 
}
 
$d = new prueba3('d');
 
$d->asignaPropiedadSecreta ($a); 
 
$d->muestraPropiedadSecreta ();

Vaya, pues vemos que accedemos igualmente a la propiedad declarada como private. ¿Cómo es posible que estemos accediendo a ellos cuando claramente la propiedad es privada y no debería de ser posible accederse a ella desde otra clase?

Pues porque estamos accediendo realmente por herencia a los métodos y propiedades originales de asignación y recuperación de la clase orginal de forma estática.

La última prueba. Volvamos a eliminar nuevamente la anterior parte y volvamos a utilizar la herencia, pero sobreescribiendo todos los métodos y propiedades.

Parte 4:

class prueba4 extends prueba {
 
  private $secreto;
 
  public function __construct ($value)
  {
    $this->secreto = $value;
  }
 
  public function asignaPropiedadSecreta ($otroObjeto)
  {
    $this->secreto = $otroObjeto->secreto;
  }
 
  public function muestraPropiedadSecreta ()
  {
    echo $this->secreto;
  } 
 
}
 
$e = new prueba4('e');
 
$e->asignaPropiedadSecreta ($a); 
 
$e->muestraPropiedadSecreta ();

Ahora sí. Nuevamente vuelve a dar un Fatal Error. Está claro que si sobreescribimos los métodos originales ya no nos encontramos dentro del ámbito de la clase original, y por lo tanto ya no podemos acceder a la propiedad original con métodos de la clase heredera.

Es como cuando te vas a casa de tus padres pero sigues yendo ha comer. Te enteras de sus secretos, pero si dejas de ir ya no tienes acceso a ellos.

Ricardo Ocaña

Bueno, espero que os haya resultado interesante y agradeceré cualquier comentario y puntualización. Por lo que parece esta implementación es igual en otros lenguajes, pero resultaría interesante cualquier prueba que podaís realizar con Java u otros.

Comparte si te ha gustado

Autor:
Última actualización:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

De acuerdo con lo dispuesto en el Reglamento (UE) 2016/679 de 27 de abril de 2016, consiento que mis datos sean tratados bajo la responsabilidad de Oscar Gascón Arjol para recibir respuesta a consultas. publicación de comentarios del blog y que las conserve mientras haya un interés mutuo para ello. Me doy por informado que tengo derecho a revocar este consentimiento en cualquier momento y a ejercer los de acceso, rectificación, portabilidad y supresión de mis datos y los de limitación y oposición al tratamiento dirigiéndome por email a me@oscargascon.es. También estoy informado de que puedo reclamar ante la autoridad de control a www.agpd.es.