PHP5 and his curious inheritance handle (OOP) PHP5 y su curiosa la manera de manejar la herencia (POO)

Mi problema inicial era por decirlo menos, “simple”. Cree unas clases para manejar “módulos” (like-joomla), “bloques” (like-phpnuke) , widgets (like-wordpress). Es decir pequeños recuadros de html que puedo poner en una barra lateral, como en este blog.
OK. Mi diseño consistió en:

  • Clase Dock: es un “área” donde se pueden encolar los widgets. Ejemplo: un leftSidebar, un menuBar, etc…
  • Clase Widget: una clase básica de la cual heredaran los demás widgets. Un Widget entonces será un pequeño espacio que retornará HTML.
  • Clases que heredan de Widget. Ejemplo: Widget_Validator, es uno que hice que retorna los botoncitos con los links para validar el html con el validador de la w3c.

Hasta ahí todo OK.

Entonces, surgió la problemática. Algunos de mis Widget_* necesitaban recursos externos (un script de vista, un modelo, una traducción, etc…). Así que pensé “OK, necesito un directorio de recursos para cada widget”. El problema está en que en algunas partes del código, tengo las instancias de los widgets, pero no necesariamente conozco su nombre de clase, pues el método $widget->getContent() es el que hace la magia de pegar el HTML en su posición. Entonces pensé “ok, necesito un método que me retorne el nombre del ‘directorio de recursos’, puede ser en base al nombre de la propia clase”.

Acá es donde pillé el EPIC FAIL:

Primer intento: Constantes de Clase

Lo primero que pensé ocupar, fue las constantes de clase.
Así era cosa de definir una constante con el nombre del directorio (está bien que sea constante, no voy a cambiar el directorio). El problema es que para acceder a la constante, se debe hacer conociendo el nombre de la clase. Por ejemplo:

Entonces encontré como hacer un método que recoja la constante de clase, a través de un método mágico:

NAME;

Perfecto, funciona. Ahora el detalle: Se supone que ese método hace referencia a sí mismo (self::). Pero en esa clase es inútil, pues necesito que me de el nombre de las clases hijas.

NAME; 
echo $child->NAME;

EPIC FAIL!!!

Mi resultado totalmente inesperado. Ambos echo’s imprimieron “Papi”. ¿No se supone que al heredar una función, es “como si fuera de la clase hija”? Entonces el “self” dentro del método mágico debería ser una referencia a la clase que llame (Child).
Para demostrar que es un error en la herencia, redefiní el método mágico en la clase hija:

Class Constants';
echo '

' . var_dump($dad->NAME) . '

'; echo '

' . var_dump($child->NAME) . '

';

CHAN!!!
Ahora ambos echo’s imprimen lo que deben imprimir: “Papi” e “Hijo”.

Segundo intento: Nombre del archivo que define a la clase (constante __FILE__)

En PHP existe una constante predefinida __FILE__ que asume el valor del nombre del archivo que se está interpretando. Si mi archivo es algo.php, al imprimir por pantalla a __FILE__ obtendremos “/ruta/a/algo/algo.php”. Si lo incluyo en index.php, igualmente imprimirá por pantalla “/ruta/a/algo/algo.php”.

Como tengo la buena costumbre (impuesta por java) de guardar cada clase en un archivo distinto, y los Widget_* no serán la excepción, entonces ocupé este factor para obtener lo que necesito: un nombre para establecer un directorio. Añadí entonces el siguiente método a mi clase Dad:


File';
echo '

' . var_dump($dad->myFile()) . '

'; echo '

' . var_dump($child->myFile()) . '

';

MISMO ERROR!!!

Imprime 2 veces el mismo nombre de archivo :S.

Tercer intento: Nombre de la clase a través de la constante __CLASS__

Ok, esto ya se volvió extraño. ¿Es el comportamiento general de la herencia en PHP5?

Durante mi “investigación”, recurri a otra constante especial, que asume un valor DENTRO de la definición de una clase. Me refiero a la constante __CLASS__. Esta toma por valor una cadena con el nombre de la clase. Hice lo mismo que con __FILE__


Class Name';
echo '

' . var_dump($dad->myClass()) . '

'; echo '

' . var_dump($child->myClass()) . '

';

Dejavu FAIL!!!

Nuevamente imprime 2 veces lo mismo que está definido en la clase Dad.

Cuarto intento: Nombre de Clase de un Objeto

Este es definitivamente el más cochino de los intentos. Se me ocurrió hacer un método que instanciará un objeto del mismo tipo que su clase, luego obtener su nombre de clase, y retornarlo. Es cochino porque gasto memoria extra, tiempo de ejecución y un símbolo inútil en la tabla interna, solo para obtener el nombre, para luego olvidar el objeto.

Class Name of an Object';
echo '

' . var_dump($dad->myName()) . '

'; echo '

' . var_dump($child->myName()) . '

';

Dejavu FAIL!!!

Nuevamente imprime 2 veces lo mismo que está definido en la clase Dad

7 comentarios sobre “PHP5 and his curious inheritance handle (OOP) PHP5 y su curiosa la manera de manejar la herencia (POO)

  1. Hm, no sé nada de PHP :P. Pero según entiendo la versión anterior si tenía la función que querías verdad?

    Si así es, ¿por qué razón en una actualización quitarían alguna característica útil?.

    Me parece bastante raro, quizá lo que buscas está definido-descrito de otra manera en PHP5 y no por ello ‘no está’.

  2. Para nada. En PHP4 La implementación de orientación a objetos era más precaria aún.

    No existía el concepto de Visibilidad (public, protected, private). No había type-hinting, no habían métodos mágicos, …

    Es cosa de leer y comparar en el mismo manual de PHP:

    OOP en PHP4: http://www.php.net/manual/es/language.oop.php

    OOP en PHP5: http://www.php.net/manual/es/language.oop5.php

    Por cierto, conozco este lenguaje desde el 2002. En aquella época habían hostings q aun usaban php3, incluso algunos scripts estaban “hechos para php3” (aunque esa época fue la etapa final de esa transición).

    En php3 derechamente NO existía la orientación a Objetos.

    Igual le tengo algo de cariño a este lenguaje. Fue el primero que aprendí y el primero con el que logre resultados útiles.

    Simplemente la Programación Orientada a Objetos no fue la prioridad desde que nació el lenguaje. A diferencia de lenguajes más “nuevos” como Python o Ruby. No descarto para nada aprender lenguajes como estos, pero no quiere decir que quiera dejar de lado PHP en el futuro.

  3. Me acabo de dar cuenta que este artículo es del 9 de agosto y recién hoy apareció en mis feeds… que raro :S (sí, te tengo en mi lector 🙂

  4. Hola Gonzalo,
    Primero felicitarte por el blog, respecto del artículo, la forma más elegante para resolver el problema es implementando solo un método en la superclase (aunque realmente no es necesario ya que el código del método es muy sencillo), te dejo el código:

    function getClassName(){
    return get_class($this);
    }

    Con ese método todos los hijos de la clase tendrán implementado un método que retorna su propio nombre de clase.
    Saludos!

  5. Es super poco comun tener que usar el mismo nombre de constantes en dos clases distintas. Por lo general, y sin miedo a equivocarme, gracias a la herencia es que las constantes de los padres sobreescriben a las de los hijos. Es casi como un asunto de piedra angular con respecto a OOP. Ademas que en programacion no debieran ocuparse constantes definidas en tiempo de ejecucion XD

    var_dump lo que hace es efectivamente rastrear el espacio de de la variable en si y devolver su valor. Aunque en este caso, es capaz de distinguir entre si pertenece al padre o al hijo. Esto es simple de entender con el ejemplo de constantes en compiladores : ambas tendran dos espacios de memoria distintos reservados para el tipo de dato.

    Creo que hay un ejemplo en C++ acerca de la herencia de constantes, pero creo que terminaba con un NO-NO. Voy a buscarlo.

    Y segun mi experiencia, polimorfismo en PHP anda, no como las herencias 😀

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.