Herramientas de usuario

Herramientas del sitio


informatica:programacion:programacion_orientada_a_objetos:php

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
informatica:programacion:programacion_orientada_a_objetos:php [2023/03/17 10:13] – [Evitar sobrescritura] tempwininformatica:programacion:programacion_orientada_a_objetos:php [2023/03/22 10:13] (actual) – [Traits (rasgos)] tempwin
Línea 211: Línea 211:
 </code> </code>
  
 +La ventaja de usar ''unset()'' para indicar explícitamente que queremos destruir un objeto es que ejecutará lo que hayamos definido en el método ''%%__%%destruct''.
 ===== Herencia ===== ===== Herencia =====
  
Línea 432: Línea 433:
 $fulanito->nombre = "Menganito"; $fulanito->nombre = "Menganito";
 $fulanito->edad = 20; $fulanito->edad = 20;
 +</code>
 +
 +==== Conversión de una clase a cadena (__toString) ====
 +
 +Por medio de la función ''%%__%%toString()'' podemos tener una cadena como salida de una instancia de una clase.
 +
 +<code php>
 +class Gato {
 +
 +    private $nombre;
 +    private $pelo;
 +    
 +    public function __construct($nombre, $pelo) {
 +    
 +        $this->nombre = $nombre;
 +        $this->pelo = $pelo;
 +    }
 +    
 +    public function __toString() {
 +        return "Mi nombre es " . $this->nombre . " y el color de mi pelo es " . $this->pelo;
 +    }
 +}
 +</code>
 +
 +<code php>
 +$benito = new Gato("Benito", "azul");
 +
 +echo $benito; // Mostrará "Mi nombre es benito y el color de mi pelo es azul"
 </code> </code>
 ===== Métodos y propiedades estáticas ===== ===== Métodos y propiedades estáticas =====
Línea 767: Línea 796:
 </code> </code>
  
-==== Carga automática con autoload ====+==== Carga automática de clases ====
  
 Al crear un fichero por clase, cuando vamos a usar muchas, una de las mayores molestias es tener que hacer una larga lista de inclusiones al comienzo de cada script (uno por cada clase). A partir de la versión 5.0.0 de PHP se pueden hacer autocargas para evitar el uso de ''include'' y ''require'' Al crear un fichero por clase, cuando vamos a usar muchas, una de las mayores molestias es tener que hacer una larga lista de inclusiones al comienzo de cada script (uno por cada clase). A partir de la versión 5.0.0 de PHP se pueden hacer autocargas para evitar el uso de ''include'' y ''require''
Línea 846: Línea 875:
  
 <WRAP center round info 60%> <WRAP center round info 60%>
-Las interfaces se suelen usar en proyectos grandes+Las interfaces en proyectos pequeños no suponen una ventaja, pero en proyectos medianos, grandes o muy grandes es de enorme importancia para comunicarse entre desarrolladores, son como un mapa en un viaje.
 </WRAP> </WRAP>
  
Línea 859: Línea 888:
 </code> </code>
  
-Implementamos un par de clases:+Implementamos un par de clases (observar el uso de la palabra reservada ''implements''):
  
 <code php> <code php>
Línea 952: Línea 981:
  
 Porque solo la propiedad ''peso'' es pública. Porque solo la propiedad ''peso'' es pública.
 +
 +===== Comparación de objetos =====
 +
 +Dos instancias de una clase son iguales si tienen los mismos atributos y valores (los valores se comparan con el operador de igualdad, ''='')
 +
 +Cuando se utiliza el operador de identidad (''===''), las variables de un objeto son idénticas sí y solo sí hacen referencia a la misma instancia de la misma clase.
 +
 +<code php>
 +class Gato {
 +
 +    public $bandera;
 +}
 +
 +class Perro {
 +
 +    public $bandera;
 +}
 +</code>
 +
 +Comparamos:
 +
 +<code php>
 +$gato1 = new Gato();
 +$gato2 = new Gato();
 +$gato3 = $gato1; // copia por referencia
 +
 +$perro1 = new Perro();
 +
 +echo "Comparamos elementos de la misma clase" . PHP_EOL;
 +
 +echo "gato1 == gato";
 +echo ($gato1 == $gato2) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +
 +echo "gato1 != gato";
 +echo ($gato1 != $gato2) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +
 +echo "gato1 === gato";
 +echo ($gato1 === $gato2) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +
 +echo "gato1 !== gato";
 +echo ($gato1 !== $gato2) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +</code>
 +
 +Resultado:
 +
 +<code>
 +Comparamos elementos de la misma clase
 +gato1 == gato Verdadero
 +gato1 != gato Falso
 +gato1 === gato Falso
 +gato1 !== gato Verdadero
 +</code>
 +
 +Compararemos elementos de la misma clase a la misma referencia:
 +
 +<code php>
 +echo "Compararemos elementos de la misma clase a la misma referencia:" . PHP_EOL;
 +
 +echo "gato1 == gato3";
 +echo ($gato1 == $gato3) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +
 +echo "gato1 != gato3";
 +echo ($gato1 != $gato3) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +
 +echo "gato1 === gato3";
 +echo ($gato1 === $gato3) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +
 +echo "gato1 !== gato3";
 +echo ($gato1 !== $gato3) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +</code>
 +
 +Resultado:
 +
 +<code>
 +Compararemos elementos de la misma clase a la misma referencia:
 +gato1 == gato3 Verdadero
 +gato1 != gato3 Falso
 +gato1 === gato3 Verdadero
 +gato1 !== gato3 Falso
 +</code>
 +
 +Finalmente, compararemos elementos de diferente clase (aunque tengan los mismos elementos):
 +
 +<code php>
 +echo "Compararemos elementos de distinta clase, pero mismas propiedades:" . PHP_EOL;
 +
 +echo "gato1 == perro1";
 +echo ($gato1 == $perro1) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +echo "gato1 != perro1";
 +echo ($gato1 != $perro1) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +echo "gato1 === perro1";
 +echo ($gato1 === $perro1) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +
 +echo "gato1 !== perro1";
 +echo ($gato1 !== $perro1) ? " Verdadero" . PHP_EOL: " Falso" . PHP_EOL;
 +</code>
 +
 +Resultado:
 +
 +<code>
 +Compararemos elementos de la misma clase a la misma referencia:
 +gato1 == perro1 Falso
 +gato1 != perro1 Verdadero
 +gato1 === perro1 Falso
 +gato1 !== perro1 Verdadero
 +</code>
 ===== Clases anónimas ===== ===== Clases anónimas =====
 +
 +Las clases anónimas no tienen nombre. Disponibles desde la versión 7 de PHP.
 +
 +Las clases anónimas son útiles para definir objetos sencillos y desechables.
 +
 +<code php>
 +$gato = new Class("Don Gato") { 
 +    private $nombre;
 +    
 +    public function __construct($nombre) {
 +        $this->nombre = $nombre;
 +    }
 +    
 +    public function getNombre() {
 +        return "Mi nombre es " . $this->nombre;
 +    }
 +};
 +
 +echo $gato->getNombre(); // Mi nombre es Don Gato
 +</code>
 +
 +===== Traits (rasgos) =====
 +
 +Por medio de los //[[https://www.php.net/manual/en/language.oop5.traits.php|traits]]// podemos reducir las limitaciones de la **herencia simple** (solo se puede heredar una clase).
 +
 +Podemos reutilizar código (conjuntos de métodos) sobre clases independientes o a jerarquía de clase diferentes.
 +
 +Un rasgo o trait es similar a las clases, pero solo agrupa métodos específicos.
 +
 +<code php>
 +interface Animal {
 +    function nacer();
 +    function crecer();
 +    function reproducir();
 +    function morir();
 +}
 +
 +abstract class Vertebrado implements Animal {
 +    private $huesos;
 +    
 +    public function getHuesos() {
 +        return $this->huesos;
 +    }
 +    
 +    public function nacer() {};
 +    public function crecer() {};
 +    public function reproducir() {};
 +    public function morir() {};
 +}
 +
 +abstract class Invertebrado implements Animal {
 +    private $hemocianina;
 +    
 +    public function getHemocianina() {
 +        return $this->hemocianina;
 +    }
 +    
 +    public function nacer() {};
 +    public function crecer() {};
 +    public function reproducir() {};
 +    public function morir() {};
 +}
 +
 +class Molusco extends Invertebrado {
 +
 +    private $radula;
 +    
 +    public function getRadula() {
 +        return $this->radula;
 +    }
 +}
 +
 +class Reptil extends Invertebrado {
 +
 +    private $escamas;
 +    
 +    public function getEscamas() {
 +        return $this->escamas;
 +    }
 +}
 +</code>
 +
 +Tanto los moluscos como los reptiles son ovíparos. Si creásemos una clase abstracta **Ovíparo**, no podríamos heredar de ella porque ya están heredando de Vertebrado y de Invertebrado (PHP solo permite herencia simple). Para este caso se usan los **traits**:
 +
 +<code php>
 +trait Oviparo {
 +
 +    private $huevos;
 +    
 +    public function getHuevos() {
 +        return $this->huevos;
 +    }
 +}
 +</code>
 +
 +Ahora podríamos hacer:
 +
 +<code php>
 +class Reptil extends Invertebrado {
 +
 +    use Oviparo; // Usamos el trait para simular herencia múltiple
 +    private $escamas;
 +    
 +    public function getEscamas() {
 +        return $this->escamas;
 +    }
 +}
 +</code>
 +
 +<WRAP center round info 60%>
 +Si vamos a usar varios **traits** los separaríamos con comas: ''use trait1, trait2, trait3;''
 +</WRAP>
 +
 +
 +Si ahora creamos una nueva clase:
 +
 +<code php>
 +class Tortuga extends Reptil {
 +}
 +</code>
 +
 +Herederá de Vertebrado, Reptil y Ovíparo.
 +
 +<WRAP center round info 60%>
 +A la creación de interfaz, clase abstracta y clases concretas es lo que se conoce como **modelado** en programación orientada a objetos.
 +</WRAP>
 +
 +===== La clase ReflectionClass =====
 +
 +Devuelve información sobre una clase.
 +
 +<code php>
 +$reflection = new ReflectionClass("Tortuga");
 +Reflexion::export($reflexion); // Devuelve información sobre la clase
 +var_dump($reflexion->isAbstract()); // Es abstracta?
 +var_dump($reflexion->isInstantiable()); // Se puede instanciar?
 +var_dump($reflexion->isInternal()); // Es interna?
 +</code>
 +
 +===== Constantes predefinidas =====
 +
 +  * %%__%%FILE%%__%%
 +  * %%__%%LINE%%__%%
 +  * %%__%%CLASS%%__%%
 +  * %%__%%TRAIT%%__%%
 +  * %%__%%METHOD%%__%%
 +  * %%__%%NAMESPACE%%__%%
 +
 +<code php>
 +
 +</code>
 +
 +===== Espacios de nombres =====
 +
 +Cuando tenemos varias clases, funciones, etc. Es común que queramos compartirlos (crear una biblioteca) y puede ocurrir que hayamos usado el mismo nombre que otras funciones o clases y al querer usarlas se produce un conflicto porque no se puede distinguir cuál es cuál.
 +
 +Los espacios de nombres (//namespaces//) son una forma de "encapsular" elementos de tal manera que se puedan distinguir de otros que podrían llamarse igual.
 +
 +Una analogía es el sistema de archivos de un disco duro:
 +
 +<code>
 +/home/tempwin/docs/letra.txt
 +/home/tempwin/music/artista/album/letra.txt
 +</code>
 +
 +Hay dos ficheros con el mismo nombre (''letra.txt''), pero están en ubicaciones diferentes por lo cual no crean conflicto.
 +
 +En PHP se utilizan los espacios de nombres para la creación de bibliotecas evitando el conflicto de nombre de funciones o variables y para simplificar nombres de elementos muy largos y evitar el primer problema en el desarrollo de código reutilizable.
 +
 +<WRAP center round info 60%>
 +Los espacios de nombres están disponibles en PHP desde 5.3.0
 +</WRAP>
 +
 +
 +Los espacios de nombres nos permiten agrupar clases, interfaces, funciones y constantes relacionadas por lo general en una biblioteca.
 +
 +==== Creación ====
 +
 +El código que se ve afectado por el espacio de nombres son las clases, interfaces, funciones y constantes.
 +
 +Se definen con la palabra reservada ''namespace'', que debe definirse antes de cualquier sentencia y no estar precedida por ningún espacio ni caracter (excepto comentarios).
 +
 +<code php>
 +namespace Perro;
 +
 +const NOMBRE = "Bobby";
 +
 +class MiPerro {
 +
 +    // Código
 +    
 +    public function pasearPerro() {
 +
 +        // Código
 +    }
 +}
 +</code>
 +
 +Podemos crear subespacios de nombres como si de directorios se tratase:
 +
 +<code php>
 +namespace Perro\salchicha;
 +
 +const NOMBRE = "Bobby";
 +
 +class MiPerro {
 +
 +    // Código
 +    
 +    public function pasearPerro() {
 +
 +        // Código
 +    }
 +}
 +</code>
 +
 +También podemos definir varios //namespaces// en un mismo fichero:
 +
 +<code php>
 +namespace Perro {
 +    
 +    const NOMBRE = "Bobby";
 +    class MiPerro {
 +
 +        // Código
 +    
 +        public function pasearPerro() {
 +
 +            // Código
 +        }
 +    }
 +}
 +    
 +namespace Gato {
 +    
 +    const NOMBRE = "Garfield";
 +    class MiGato {
 +
 +        // Código
 +    
 +        public function pasearGato() {
 +
 +            // Código
 +        }
 +    }
 +}
 +</code>
 +
 +==== Llamada a un espacio de nombres ====
 +
 +El manejo de los espacios de nombres es muy similar al uso de un sistema de ficheros de un disco duro:
 +
 +  * Llamar al archivo sin indicar ruta
 +  * Llamar al archivo con una ruta relativa
 +  * Llamar al archivo con una ruta absoluta
 +
 +Creamos el namespace (''fichero1.php''):
 +
 +<code php>
 +namespace Animal\Perro\salchica;
 +
 +const NOMBRE = "Cinnamon";
 +
 +function comer () {
 +    echo "Estoy comiendo, Cinnamon";
 +}
 +
 +class Pasear {
 +    static function paseo() {
 +        echo "Estoy paseando, Cinnamon";
 +    }
 +}
 +</code>
 +
 +En otro fichero (''fichero2.php''):
 +
 +<code php>
 +namespace Animal\Perro;
 +
 +include "fichero1.php";
 +
 +const NOMBRE = "Perro";
 +
 +
 +function comer () {
 +    echo "Estoy comiendo, perro";
 +}
 +
 +class Pasear {
 +    static function paseo() {
 +        echo "Estoy paseando, perro";
 +    }
 +}
 +</code>
 +
 +Si ahora hacemos lo siguiente:
 +
 +<code php>
 +// Nombre no cualificado
 +comer();
 +Pasear::paseo();
 +echo NOMBRE;
 +</code>
 +
 +Se usa el del ''fichero2.php''.
 +
 +Si ahora hacemos:
 +
 +<code php>
 +// Nombre cualificado
 +salchicha\comer();
 +salchicha\Pasear::paseo();
 +echo salchicha\NOMBRE;
 +</code>
 +
 +Se usará el del ''fichero1.php''
 +
 +Finalmente:
 +
 +<code php>
 +// Nombre completamente cualificado
 +\Animal\Perro\salchicha\comer();
 +\Animal\Perro\salchicha\Pasear::paseo();
 +echo \Animal\Perro\salchicha\NOMBRE;
 +</code>
 +
 +<WRAP center round tip 60%>
 +La constante ''%%__%%NAMESPACE%%__%%'' contiene el espacio de nombres actual.
 +</WRAP>
 +
 +==== Alias con use ====
 +
 +Desde PHP 5.3.0 se ofrecen varias formas de crear alias para apodar una clase, interfaz o espacio de nombres.
 +
 +Empleamos la palabra reservada ''use''.
 +
 +Por ejemplo, suponiendo que tenemos un fichero PHP con el namespace ''Animales\Mamiferos'', en un nuevo fichero podemos crear un alias del mismo de la siguiente manera:
 +
 +<code php>
 +use Animales\Mamiferos as mascota;
 +use function Animales\Mamiferos\ladrar as ladrido;
 +use const Animales\Mamiferos\PERRO as DOG;
 +
 +$perro = new mascota\Perro;
 +ladrido();
 +echo DOG;
 +</code>
 +
 +==== Espacio de nombres global ====
 +
 +Puede ocurrir que definamos una función o clase que se llame igual que una interna de PHP. Para distinguir la interna, usamos ''\'':
 +
 +<code php>
 +namespace MiNamespace\miSubNamespace;
 +
 +function fopen($archivo) {
 +    $f = \fopen($archivo);
 +    return $f;
 +}
 +
 +class Exception extends \Exception {};
 +
 +$e = new Exception("Hola"); // la clase del namespace
 +$e2 = new \Exception("Hola, otra vez"); // La clase global
 +</code>
 ===== Funciones interesantes ===== ===== Funciones interesantes =====
  
Línea 959: Línea 1467:
   * ''get_class_methods()'': muestra los métodos de una clase.   * ''get_class_methods()'': muestra los métodos de una clase.
   * ''method_exists()'': indica si un método existe en una clase específica.   * ''method_exists()'': indica si un método existe en una clase específica.
-  * ''get_class()'': indica la clase a la que pertenece la instancia.+  * ''get_class()'': indica la clase a la que pertenece la instancia. También se puede usar ''$objeto::class''.
   * ''is_a()'': indica si una instancia pertenece a cierta clase.   * ''is_a()'': indica si una instancia pertenece a cierta clase.
   * ''get_parent_class()'': devuelve la clase origen o padre de la clase solicitada.   * ''get_parent_class()'': devuelve la clase origen o padre de la clase solicitada.
   * ''is_subclass_of()'': indica si las clases están en la misma jerarquía de clase.   * ''is_subclass_of()'': indica si las clases están en la misma jerarquía de clase.
informatica/programacion/programacion_orientada_a_objetos/php.1679044395.txt.gz · Última modificación: por tempwin