Foros del Web » Programando para Internet » PHP » Frameworks y PHP orientado a objetos »

PHP y su curiosa manera de manejar la herencia

Estas en el tema de PHP y su curiosa manera de manejar la herencia en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Hace unas semanas publiqué en mi blog una experiencia extraña que tuve con PHP5 y la orientación a objetos. Básicamente, se trata de un problema ...
  #1 (permalink)  
Antiguo 08/09/2008, 14:24
Avatar de ArrauKano  
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago
Mensajes: 664
Antigüedad: 21 años, 5 meses
Puntos: 4
PHP y su curiosa manera de manejar la herencia

Hace unas semanas publiqué en mi blog una experiencia extraña que tuve con PHP5 y la orientación a objetos.

Básicamente, se trata de un problema de la herencia y el polimorfismo. Por un au otra razón, me vi en la necesidad de obtener información sobre la clase que definía a un objeto. Entonces se me ocurrió implementar métodos en estas clases que retornaran la información que necesitaba.

Para efectos simples, supongamos que tengo 2 clases, Papa e Hijo, más un archivo de pruebas.

Algo así:

Dad.php
Código PHP:
<?php

class Dad {

  const 
NAME 'Papi';

  
// Magic Method to access a class constant
  
private function __get($name)
  {
    if(
defined("self::$name"))
    {
      return 
constant("self::$name");

    }
    
trigger_error ("$name  isn't defined");
  }

  public function 
myFile()
  {
    return  
__FILE__ ;
  }
  
  public function 
myClass()
  {
    return 
__CLASS__;
  }

  public function 
myName()
  {
    
$me = new self;
    return 
get_class($me);
  }
}
Child.php
Código PHP:
<?php
require_once 'Dad.php' ;

class 
Child extends Dad
{
  const 
NAME 'Hijo';

  public function 
myFile()
  {
    return 
__FILE__;
  }

}
test.php

Código PHP:
<?php
require_once 'Child.php' ;
require_once 
'Dad.php' ;
 
$dad = new Dad();
$child = new Child();

echo 
'<h1>Class Constants</h1>';
echo 
'<p>' var_dump($dad->NAME) . '</p>';
echo 
'<p>' var_dump($child->NAME) . '</p>';

echo 
'<h1>File</h1>';
echo 
'<p>' var_dump($dad->myFile()) . '</p>';
echo 
'<p>' var_dump($child->myFile()) . '</p>';

echo 
'<h1>Class Name</h1>';
echo 
'<p>' var_dump($dad->myClass()) . '</p>';
echo 
'<p>' var_dump($child->myClass()) . '</p>';

echo 
'<h1>Class Name of an Object</h1>';
echo 
'<p>' var_dump($dad->myName()) . '</p>';
echo 
'<p>' var_dump($child->myName()) . '</p>';
OK. ¿Donde está el problema?

Al ejecutar test.php, me di cuenta que, ninguna de las constantes especiales __FILE__ o __CLASS__, ni $this, ni self retornaron el resultado esperado.

Si llamaba los métodos desde la clase hija, seguían comportándose como si se estuvieran llamando desde la clase padre, EXCEPTO si redefinía en la clase hija el mismo método, con el mismo código.

No se si esto es un "bug" o es la implementación habitual de OOP en PHP5, pero hasta ahora, me ha pasado lo mismo en distintas versiones de PHP5 (no he probado en PHP4).

¿Ustedes que creen? ¿Será algo que deba cambiarse en el futuro PHP6?
__________________
Blog | Tecnosquad
  #2 (permalink)  
Antiguo 08/09/2008, 14:50
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 17 años, 11 meses
Puntos: 2135
Respuesta: PHP y su curiosa manera de manejar la herencia

Hola ArrauKano,

Si ves el manual, puedes ver que es el comportamiento esperado de las variables y esto es para tener el scoping claro y tener una base.

Si realmente deseas obtener esa información lo mejor es implementar Reflection, ya que para eso se creo el API.

Saludos.
  #3 (permalink)  
Antiguo 08/09/2008, 16:26
Avatar de ArrauKano  
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago
Mensajes: 664
Antigüedad: 21 años, 5 meses
Puntos: 4
Respuesta: PHP y su curiosa manera de manejar la herencia

Justamente pensé en el tema del ámbito. Según lo que tenía entendido por herencia/polimorfismo, el comportamiento que observé de PHP5 violaría esos principios, pero si es el comportamiento habitual, entonces tendré que conformarme.
__________________
Blog | Tecnosquad
  #4 (permalink)  
Antiguo 09/09/2008, 08:28
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 17 años, 11 meses
Puntos: 2135
Respuesta: PHP y su curiosa manera de manejar la herencia

¿Porque violarlos?, si te fijas son constantes especiales, en ningúna parte de los principios de la OOP se especifica el comportamiento de una constante especial del lenguaje.

La decisión de que se refieran a la clase donde fueron definidas es para saber donde estas parado a la hora de hacer alguna función con una clase. Es por lo mismo que no puedes diseñar una clase con singleton, y al heredarla esperar que funcione ya que self, se referira a la clase padre.

Si realmente necesitas obtener esos datos desde la clase hija, por eso existe Reflection para tener un API claro para poder trabajar (y desde una implementación OOP).

Saludos.
  #5 (permalink)  
Antiguo 09/09/2008, 16:41
 
Fecha de Ingreso: enero-2006
Ubicación: Buenos Aires, Argentina
Mensajes: 299
Antigüedad: 18 años, 3 meses
Puntos: 5
Respuesta: PHP y su curiosa manera de manejar la herencia

A mí a primera vista también me pareció "contra-intuitivo". No necesariamente la parte que involucra constantes, sino que $this en el método de la clase base se refiera a una variable declarada en la clase base y no a la variable de la clase que hereda, cuando se está trabajando sobre una instancia de la clase heredada.

O sea, en código:

Código PHP:
class Dad {

  private 
$className "Dad";
  
  public function 
getClassName() {
    return 
$this->className;
  }
  


class 
Child extends Dad {

  private 
$className "Child";



$dad = new Dad();
$child = new Child(),

echo 
"dad: " $dad->getClassName() . "<br>";        //  --> Dad
echo "child : " $child ->getClassName() . "<br>";   //  ---> Dad 
Viendo el código, yo esperaría que $child ->getClassName() devolviera "Child", en vez de "Dad".

Decidí hacer unas pruebas con otros lenguajes -- algunos de los cuales uso habitualmente (ActionScript 2 & 3, C#), y otros que uso ocasionalmente o sólo usé alguna vez y no podría decir que los conozco a fondo, sólo lo básico para compilar una prueba (Java, C++, python).

Siempre usando el mismo código (adaptando la sintaxis, obviamente, pero respetando la estructura), el resultado me sorprendió. Excepto ActionScript 2.0 y Python, en el resto de las pruebas los resultados son iguales a los que se obtienen en PHP. Es decir, this.className en el método getClassName() de una instancia de Child se refiere a Dad::className, no a Child::className.

En síntesis, this.className se resuelve así:

ActionScript 2.0 --> Child
Python --> Child

PHP --> Dad
ActionScript 3.0 --> Dad
C# / .NET --> Dad
Java --> Dad
C++ --> Dad


Si alguien tiene una explicación "técnica" sobre el porqué de este comportamiento (que a mí particularmente me resulta "contra-intuitivo", como dije, pero que creo que es el más standard según estas pruebas), se lo agradecería. Es sólo curiosidad.


Saludos
Juan Pablo Califano
  #6 (permalink)  
Antiguo 09/09/2008, 16:57
 
Fecha de Ingreso: enero-2006
Ubicación: Buenos Aires, Argentina
Mensajes: 299
Antigüedad: 18 años, 3 meses
Puntos: 5
Respuesta: PHP y su curiosa manera de manejar la herencia

PD:

Usando la sintaxis de php4 (tanto usando como intérprete una versión php4 o php5), el resultado es distinto.

Código PHP:
class Dad {

  var 
$className "Dad";
  
  function 
getClassName() {
    return 
$this->className;
  }
  


class 
Child extends Dad {

  var 
$className "Child";



$dad = new Dad();
$child = new Child();

echo 
"dad: " $dad->getClassName() . "<br>";        //  --> Dad
echo "child : " $child->getClassName() . "<br>";   //  ---> Child 
Me parece que la clave está en "private". Porque aún con sintaxis de php5, si las variables se declaran públicas (public $className = "Hijo"), $child->getClassName() sigue trayendo Child...
  #7 (permalink)  
Antiguo 09/09/2008, 18:54
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 17 años, 11 meses
Puntos: 2135
Respuesta: PHP y su curiosa manera de manejar la herencia

Hola califa010,

Prueba poner la variable como protected, recuerda que las variables privadas NO se heredan, ya que son privadas y se pertenecen a la clase que las declara.

Las variables protegidas SI se heredan y pueden ser leídas desde las clases hijas, al igual que las variables publicas, solo que las protegidas no se pueden leer fuera de la instancia.

Saludos.
  #8 (permalink)  
Antiguo 09/09/2008, 19:15
 
Fecha de Ingreso: enero-2006
Ubicación: Buenos Aires, Argentina
Mensajes: 299
Antigüedad: 18 años, 3 meses
Puntos: 5
Respuesta: PHP y su curiosa manera de manejar la herencia

Gracias, GatorV, buen punto, no lo había tenido en cuenta (el hábito de AS 2.0, donde private en realidad sería lo que es protected en php5, Java, C#, etc).

Volviendo al ejemplo de php, usando protected el resultado es el mismo que si se usa public (o sea, child->getClassName() devuelve "Child", no "Dad").

De todos modos, volví a hacer las mismas pruebas en Java y en C# con protected en vez de private y el resultado sigue igual que en la primera prueba (en C# hay que agregar una palabra clave en la declaración de la clase heredada (new) porque si no no compila, pero el funcionamiento es igual).

De todas formas, no es que tenga un problema en concreto, simplemente me resultó curioso. Ahora entiendo la lógica de los resultados de las pruebas, si se usa private (o sea, no se hereda), aunque todavía no me queda claro por qué sigue resolviéndose this.className en child.getClaseName() como "Child" en vez de "Dad" si los campos sin heredados (protected o public).

Saludos
Juan Pablo Califano
  #9 (permalink)  
Antiguo 09/09/2008, 20:10
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 17 años, 11 meses
Puntos: 2135
Respuesta: PHP y su curiosa manera de manejar la herencia

Se resuelve como child porque estas sobrecargando la variable en la clase hija, por lo que al tu heredar la clase, llamas al método, y el método busca la variable primero en la clase heredada, al no encontrarlo, entonces lo busca en el padre.

Saludos.
  #10 (permalink)  
Antiguo 10/09/2008, 04:20
Avatar de anlhp  
Fecha de Ingreso: agosto-2008
Mensajes: 121
Antigüedad: 15 años, 8 meses
Puntos: 1
Exclamación Respuesta: PHP y su curiosa manera de manejar la herencia

bien señores, una vez mas, parece ser que soy algun tipo de mesías de los constructores o algo :D , si existen los constructores, es por algo.
Al emplear lo siguiente:

class Dad {

private $className = "Dad";

public function getClassName() {
return $this->className;
}

}

class Child extends Dad {

private $className = "Child";

}

$dad = new Dad();
$child = new Child(),

echo "dad: " . $dad->getClassName() . "<br>"; // --> Dad
echo "child : " . $child ->getClassName() . "<br>"; // ---> Dad

pues bien, rapido que tengo que trabajar jejeje,esta claro pensar en primera instancia que algo esta mal, pues heredo un metodo que que tiene que devolver el nombre de mi clase, pero sucede que en nuestra querida clase estamos creando una variable exactamente igual y no estamos sobrecargando el metodo, por lo que php nota cierta ambiguedad en las variables y al final termina devolviendonos la variable de la clase en la que se define el metodo, por tanto señores, para evitar esta 'ambiguedad' utilicemos los constructores y protected que pa eso estan:

class Dad {

protected $className = "Dad";

public function __construct(){
$this->className = 'Dad;
}
public function getClassName() {
return $this->className;
}

}

class Child extends Dad {

public function __construct(){
$this->className = 'Child;
}

}

$dad = new Dad();
$child = new Child(),

echo "dad: " . $dad->getClassName() . "<br>"; // --> Dad
echo "child : " . $child ->getClassName() . "<br>"; // ---> Child

debe funcionar, no lo he probado, como dije, eo trabajo me llama, suerte ;)
  #11 (permalink)  
Antiguo 10/09/2008, 05:01
Avatar de anlhp  
Fecha de Ingreso: agosto-2008
Mensajes: 121
Antigüedad: 15 años, 8 meses
Puntos: 1
De acuerdo Respuesta: PHP y su curiosa manera de manejar la herencia

rapidito, pues si que funciona, esperado pero bueno, da tranquilidad:
exactamente lo probe asi:

<?php
define('br','<br />');

class a {
protected $name;

public function __construct(){
$this->name = 'a';
}

public function __toString(){
return $this->name;
}
}

class b extends a{

public function __construct(){
$this->name = 'b';
}
public function __toString(){
return $this->name;
}
}

$a = new a();
$b = new b();

echo $a.br.$b;
?>
  #12 (permalink)  
Antiguo 10/09/2008, 11:27
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 17 años, 11 meses
Puntos: 2135
Respuesta: PHP y su curiosa manera de manejar la herencia

Hola anlhp,

Si defines la variable como protected, no es necesario declarar el constructor, si te fijas es el comportamiento natural o como por ejemplo levantas un Zend_Db_Table:
Código PHP:
class Bugs extends Zend_Db_Table {
       protected 
$_name 'bugs';

       protected 
$_primary 'bug_id';
}

$bugs = new Bugs();
$bug $bugs->find(5); 
Si tu defines tu variable como protected, al sobrecargarla en la clase hija, los metodos nuevos se veran afectados con los nuevos valores.

Saludos.
  #13 (permalink)  
Antiguo 10/09/2008, 17:50
Avatar de ArrauKano  
Fecha de Ingreso: noviembre-2002
Ubicación: Santiago
Mensajes: 664
Antigüedad: 21 años, 5 meses
Puntos: 4
Respuesta: PHP y su curiosa manera de manejar la herencia

Tienen razón, salvo que tanto con protected como private, si funciona.

Pero esto gracias a que la propiedad está sobrecargada en la clase hija.

Bueno, si le doy $protected y no hago ningún método que lo cambie, obtengo el mismo efecto que usando una constante de clase.

Gracias. Esta buena esta discusión.
__________________
Blog | Tecnosquad
  #14 (permalink)  
Antiguo 10/09/2008, 20:04
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 17 años, 11 meses
Puntos: 2135
Respuesta: PHP y su curiosa manera de manejar la herencia

Es por lo que te decia las constantes "magicas" de PHP estan "atadas" a la clase que las definio, por eso si lo necesitas obtener en el hijo (las constantes magicas) usa reflection.

Saludos.
  #15 (permalink)  
Antiguo 11/09/2008, 08:17
Avatar de anlhp  
Fecha de Ingreso: agosto-2008
Mensajes: 121
Antigüedad: 15 años, 8 meses
Puntos: 1
Respuesta: PHP y su curiosa manera de manejar la herencia

si, es cierto lo que dicen, el constructor en las clases los utilizo para inicializar la variable protected me entienden?, ya que quiero que esta variable me muestre cosas diferentes segun la clase de la que la llame, pero si tienen razon, no es que sea necesario el constructor, pero bueno, tengan en cuenta que programaba en c++ y los constructores me han creado un trauma serio jejeje ;)
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 05:47.