Herencia de clases en PHP. Herencia en PHP. Llamar a un método de superclase desde una clase secundaria

Marco de arranque: diseño adaptable rápido

Curso en vídeo paso a paso sobre los conceptos básicos diseño adaptativo en el marco Bootstrap.

Aprende a componer de forma sencilla, rápida y eficaz utilizando una potente y práctica herramienta.

Diseño para ordenar y recibir pagos.

Curso gratuito "Sitio en WordPress"

¿Quieres dominar el CMS de WordPress?

Obtenga lecciones sobre diseño y maquetación de sitios web en WordPress.

Aprenda a trabajar con temas y diseños de corte.

¡Curso en video gratuito sobre cómo dibujar, diseñar e instalar un sitio web en CMS WordPress!

*Pase el mouse sobre para pausar el desplazamiento.

Atrás Adelante

Herencia en PHP

La herencia es un mecanismo mediante el cual una o más clases pueden derivarse de alguna clase base.

Una clase que se obtiene heredando de otra se llama subclase de ésta. Esta relación suele describirse utilizando los términos "padre" e "hijo".

Una clase hija se deriva de una clase padre y hereda sus características. Estas características consisten en propiedades y métodos.

Normalmente, una clase secundaria agrega nueva funcionalidad a la clase principal (también llamada superclase). funcionalidad. Por lo tanto, se dice que la clase hija extiende la clase padre.

Antes de comenzar a aprender sobre la sintaxis de herencia, veamos los problemas que puede ayudarnos a resolver.


problema de herencia

volvamos a clase TiendaProducto. Actualmente está bastante generalizado. Con su ayuda podrá manipular una amplia variedad de productos.

$producto1 = new ShopProduct("Corazón de perro", "Mikhail", "Bulgakov", 5,99); $producto2 = new ShopProduct("Falta", "Grupo", "DDT", 10.99); print "Autor: ".$producto1->getProducer()."\n"; print "Productor: ".$producto2->getProducer()."\n";

El resultado es el siguiente.

La pereza es una estrategia de diseño distintiva, por lo que en esta etapa no tienes que preocuparte por usar la clase TiendaProducto para más de un tipo de producto.

Pero si en nuestro ejemplo agregamos varios requisitos nuevos, inmediatamente todo se volverá más complicado. Imaginemos que necesitamos mostrar datos específicos de libros y álbumes de música.

Digamos que para un álbum es deseable mostrar tiempo total sonido, y para un libro, el número total de páginas. Por supuesto, puede haber otras diferencias, pero éstas ilustran bien la esencia del problema.

¿Cómo podemos ampliar nuestro ejemplo para dar cabida a estos cambios? Inmediatamente me vienen a la mente dos opciones. Primero, puedes poner todos los datos en una clase. TiendaProducto. En segundo lugar, puedes romper TiendaProducto en dos clases separadas.

Veamos el primer enfoque. Entonces, combinamos datos sobre libros y álbumes de música en una clase.

Clase ShopProduct ( public $numPages; public $playLength; public $title; public $producerMainName; public $producerFirstName; public $price; function __construct($title, $firstName, $mainName, $price, $numPages=0, $playLength= 0) ( $this->title = $title; $this->producerFirstName = $firstName; $this->producerMainName = $mainName; $this->price = $price; $this->numPages = $numPages; $this ->playLength = $playLength; ) función getNumberOfPages() ( return $this->numPages; ) función getPlayLength() ( return $this->playLength; ) función getProducer() ( return "($this->producerFirstName)". " ($this->nombreprincipaldelproductor)";

Para demostrar la gran cantidad de trabajo de codificación involucrado, en este ejemplo Se utilizaron métodos de acceso a la propiedad. $numPáginas Y $playLength.

Como resultado, un objeto instanciado utilizando dicha clase siempre contendrá métodos redundantes. Además, para un álbum de música, sería necesario crear una instancia del objeto utilizando un argumento de constructor sin sentido.

Por lo tanto, para los álbumes, se almacenará información de clase y funcionalidad relacionada con los libros (número total de páginas), y para los libros, se almacenará información sobre el tiempo de reproducción de los álbumes.

Probablemente puedas vivir con ello por ahora. Pero ¿qué pasa si sumamos más tipos productos, cada uno con sus propios métodos, y luego agregar más métodos para cada tipo? Nuestra clase será cada vez más compleja y difícil de usar.

Por lo tanto, forzar la fusión de propiedades relacionadas con diferentes bienes, en una clase conducirá a la creación de objetos demasiado engorrosos con propiedades y métodos innecesarios.

Pero los problemas no terminan ahí. También habrá dificultades con la funcionalidad.

Imagine un método que genere breve información sobre el producto. Digamos que el departamento de ventas necesita información del producto de una sola línea para usarla en una factura. Quieren que incluyamos tiempos de reproducción de álbumes y recuentos de páginas de libros.

Así, a la hora de implementar este método, tendremos que tener en cuenta el tipo de cada producto. Se puede utilizar una bandera especial para rastrear el formato de un objeto. Pongamos un ejemplo.

Función getSummaryLine() ( $base = "($this->title) (($this->producerMainName), "; $base .= "($this->producerFirstName))"; if ($this->type = = "libro") ( $base .= ": páginas - ($this->numPages)"; ) else if ($this->type == "cd") ( $base .= ": tiempo de reproducción - ($ this->playLength)"; ) devuelve $base; )

Como puede ver, para establecer el valor de la propiedad correctamente $tipo, necesitaremos verificar el valor del argumento en el constructor $numPáginas. Y otra vez clase TiendaProducto se ha vuelto más complejo de lo necesario.

A medida que agreguemos más diferencias en formatos o nuevos formatos, tendremos dificultades para mantenernos al día con la implementación de este método. Por lo tanto, aparentemente, para resolver este problema es necesario aplicar el segundo enfoque.

Porque TiendaProducto está empezando a parecerse a "dos clases en una", deberíamos reconocer esto y crear dos tipos en lugar de uno. He aquí cómo hacerlo.

Clase CdProduct ( public $playLength; public $title; public $producerMainName; public $producerFirstName; public $price; function __construct($title, $firstName, $mainName, $price, $playLength) ( $this->title = $title ; $this->productorFirstName = $firstName; $this->producerMainName; $this->precio = $this->playLength; función getPlayLength() ( return $this->playLength; ) función getSummaryLine() ( $base = " $this->title ($this->producerMainName, "; $base .= "$this->producerFirstName)"; $base .= ": tiempo de reproducción - $this-> playLength"; return $base; ) función getProducer () ( return "($this->producerFirstName)". " ($this->producerMainName)"; ) ) clase BookProduct ( public $numPages; public $title; public $producerMainName ; public $producerFirstName; public $price; function __construct($título, $primerNombre, $nombreprincipal, $precio, $numPáginas) ( $this->título = $título; $this->producerFirstName = $firstName; $this->productMainName = $mainName;

$this->precio = $precio;

Ahora podemos crear un método. obtenerLíneaResumen() para cada tipo de producto, y ni siquiera necesitamos comprobar el valor de una bandera especial. Y ninguna otra clase contiene campos (propiedades) o métodos que no estén relacionados con ella.

Y el sacrificio fue la duplicación. Métodos obtenerProductor() absolutamente igual para cada clase. Cada constructor establece una serie de propiedades idénticas de la misma manera. Este es otro signo de mal gusto y debes aprender a deshacerte de él.

Si es necesario, ambos métodos obtenerProductor() funcionó igual para cada clase, entonces cualquier cambio realizado en una implementación debe realizarse en la otra. Pero de esta forma pronto romperemos la sincronización de clases.

Incluso si confiamos en que podemos mantener la duplicación, nuestros problemas no terminarán ahí. Al fin y al cabo, ahora tenemos dos tipos, no sólo uno.

recordar clase TiendaProductoEscritor? Su método escribir() diseñado para trabajar con un tipo: TiendaProducto. ¿Cómo salir de esta situación para que todo funcione como antes?

Podemos eliminar la calificación del tipo de clase de la declaración del método, pero luego debemos esperar que el método escribir() Se pasará un objeto del tipo correcto.

Podemos agregar al cuerpo del método. código propio para comprobar el tipo.

Clase ShopProductWriter ( función pública escribir ($shopProduct) ( if (! ($shopProduct instancia de CdProduct) && ! ($shopProduct instancia de BookProduct)) ( die("Se pasó tipo de datos no válido"); ) $str = "($shopProduct-> título): " . $shopProduct->getProducer() . " (($shopProduct->precio))\n"; print $str; ) )

Preste atención al operador. instancia de, utilizado en este ejemplo. El valor se sustituye en su lugar. verdadero(verdadero) si el objeto del operando de la izquierda es del tipo representado por el operando de la derecha.

Y nuevamente nos vimos obligados a agregar nuevo nivel complejidad. Necesitamos no sólo comprobar el argumento $tiendaProducto para el cumplimiento de dos tipos en el método escribir(), pero también esperamos que cada tipo admita los mismos campos y métodos que el otro.

De acuerdo, tener un solo tipo sería mucho mejor porque podríamos usar el refinamiento del tipo de clase para el argumento del método. escribir(), y estaríamos seguros de que la clase TiendaProducto Soportaba una interfaz específica.

Características de clase TiendaProducto, asociados con libros y álbumes de música, no funcionan bien juntos, pero parece que no pueden existir por separado.

Necesitamos tratar libros y álbumes como un solo tipo, pero al mismo tiempo proporcionar una implementación de método separada para cada formato de salida.

Necesitamos crear una funcionalidad común en un solo lugar para evitar la duplicación, pero al mismo tiempo asegurarnos de que al llamar a un método que muestra información breve sobre un producto, se tengan en cuenta las características de formato. En resumen, necesitamos utilizar la herencia.

PD Claramente quieres entender PHP y OOP) Presta atención a las lecciones premium sobre varios aspectos creación de sitios web, incluida la programación en PHP, así como curso gratis sobre cómo crear su propio sistema CMS en PHP desde cero usando programación orientada a objetos:

¿Te gustó el material y quieres agradecerme?
¡Simplemente comparte con tus amigos y colegas!


La herencia es un mecanismo basado en objetos. programación orientada, que nos permite describir nueva clase basado en uno existente (padre).

Una clase que se obtiene heredando de otra se llama subclase. Esta relación suele describirse utilizando los términos "padre" e "hijo". Una clase hija se deriva de una clase padre y hereda sus características: propiedades y métodos. Normalmente, una subclase agrega nueva funcionalidad a la funcionalidad de la clase principal (también llamada superclase).

Para crear una subclase, debes usar la palabra clave extends en la declaración de clase, seguida del nombre de la clase de la que estás heredando:

edad = $edad;
) function add_age () ( $this->age++; ) ) // declara una clase heredada class my_Cat extends Cat ( // define nuestro propio método de subclase function sleep() ( echo "

Zzzzz..."; ) ) $kitty = new my_Cat(10); // llama al método heredado $kitty->add_age(); // lee el valor de la propiedad heredada echo $kitty->age; // llama el método propio de la subclase $ kitty->sleep();

La subclase hereda el acceso a todos los métodos y propiedades de la clase principal, ya que son de tipo público. Esto significa que para instancias de la clase my_Cat, podemos llamar al método add_age() y acceder a la propiedad $age, aunque estén definidas en la clase cat. Además, en el ejemplo anterior, la subclase no tiene su propio constructor. Si la subclase no declara su propio constructor, al crear instancias de la subclase, se llamará automáticamente al constructor de la superclase.

edad"; ) ) clase my_Cat extiende Cat ( public $edad = 10; ) $kitty = new my_Cat; $kitty->foo(); ?>

Al llamar a $kitty->foo(), el intérprete PHP no puede encontrar dicho método en la clase my_Cat, por lo que se utiliza la implementación de este método definido en la clase Cat. Sin embargo, la subclase define su propia propiedad $age, por lo que cuando se accede a ella en el método $kitty->foo(), el intérprete PHP encuentra esa propiedad en la clase my_Cat y la usa.

Como ya hemos cubierto el tema de especificar el tipo de argumentos, queda por decir que si la clase principal se especifica como el tipo, entonces todos los descendientes del método también estarán disponibles para su uso; mire el siguiente ejemplo:

foo(nuevo mi_gato); ?>

Podemos tratar una instancia de la clase my_Cat como si fuera un objeto de tipo Cat, es decir podemos pasar un objeto de tipo my_Cat al método foo() de la clase Cat y todo funcionará como se esperaba.

operador padre

En la práctica, es posible que las subclases necesiten ampliar la funcionalidad de los métodos de la clase principal. Al extender la funcionalidad anulando los métodos de la superclase, en las subclases se conserva la capacidad de ejecutar primero código de programa clase principal y luego agregar código que implemente funcionalidad adicional. Veamos cómo se puede hacer esto.

para llamar método deseado desde una clase principal, necesitará acceder a esa clase a través de un descriptor. PHP proporciona la palabra clave principal para este propósito. El operador principal permite que las subclases accedan a los métodos (y constructores) de la clase principal y agreguen funcionalidad a su existente. Para hacer referencia a un método en el contexto de una clase, utilice los símbolos "::" (dos dos puntos). La sintaxis del operador principal es:

Método padre::parent_class

Esta construcción llamará a un método definido en la superclase. Después de esta llamada, puede colocar su propio código de programa que agregará nuevas funciones:

título = $título;
$this->precio = $precio;
) ) clase new_book extiende libro ( public $pages; function __construct($title, $price, $pages) ( // llama al método constructor de la clase padre parent::__construct($title, $price); // inicializa el propiedad definida en la subclase $this->pages = $pages ) ) $obj = new new_book("ABC", 35, 500);

Cuando una clase secundaria define su propio constructor, PHP no llama automáticamente al constructor de la clase principal. Esto debe hacerse manualmente en el constructor de la subclase. La subclase primero llama al constructor de su clase padre en su constructor, pasa los argumentos necesarios para la inicialización, lo ejecuta y luego ejecuta el código que implementa funcionalidad adicional, en en este caso inicializa una propiedad de la subclase.

La palabra clave parent se puede utilizar no sólo en constructores, sino también en cualquier otro método cuya funcionalidad se quiera ampliar, esto se puede lograr llamando al método de la clase padre:

nombre)."; return $cadena; ) ) clase my_Cat extiende Cat ( public $edad = 5; función getstr() ( $cadena = parent::getstr(); $cadena .= "
Edad: ($this->age) años."; return $str; ) ) $obj = new my_Cat; echo $obj->getstr(); ?>

Aquí, primero se llama al método getstr() de la superclase, cuyo valor se asigna a una variable, y luego se ejecuta el resto del código definido en el método de la subclase.

Ahora que hemos cubierto los conceptos básicos de la herencia, finalmente podemos abordar el tema de la visibilidad de propiedades y métodos.

público, protegido y privado: control de acceso

Hasta este punto, hemos declarado explícitamente todas las propiedades como públicas. Y este tipo de acceso está configurado de forma predeterminada para todos los métodos.

Los miembros de una clase pueden declararse públicos, protegidos o privados. Veamos la diferencia entre ellos:

  • A público Se puede acceder a las propiedades y métodos (públicos) desde cualquier contexto.
  • A protegido Se puede acceder a las propiedades y métodos (protegidos) desde la clase contenedora o desde su subclase. Ninguno código externo no se proporciona acceso a ellos.
  • Puede hacer que los datos de la clase sean inaccesibles para programa de llamadas usando palabra clave privado(cerrado). Solo se puede acceder a dichas propiedades y métodos desde la clase en la que están declarados. Incluso las subclases de esta clase no tienen acceso a dichos datos.

público - acceso abierto:

hola"; ) ) $obj = new human; // acceso desde el programa de llamada echo "$obj->age"; // Válido $obj->say(); // Válido?>

privado: acceso solo desde métodos de clase:

age"; ) ) $obj = new human; // no hay acceso directo a datos privados desde el programa que llama echo "$obj->age"; // ¡Error! ¡Acceso denegado! // sin embargo, usando el método que puedes mostrar datos privados $obj ->say(); // ¿Aceptable?>

protegido - acceso protegido:

El modificador protegido, desde el punto de vista del programa que llama, tiene exactamente el mismo aspecto que el privado: prohíbe el acceso a los datos del objeto desde el exterior. Sin embargo, a diferencia del privado, le permite acceder a datos no sólo de los métodos de su clase, sino también de los métodos de una subclase.

Esta es la segunda parte de nuestro tutorial sobre objetos en PHP. La primera parte está aquí: objetos en PHP.

¿Qué es la herencia en PHP?

Usando la herencia, podemos crear clases que contendrán todas las propiedades y métodos de la clase principal. Es decir, clases infantiles. heredar propiedades y métodos de la clase padre.

Una clase hija es una extensión de la clase padre, ya que además de las propiedades y métodos heredados, contiene los suyos propios.

La herencia se establece mediante el uso de la palabra extiende al crear una clase.

Ejemplo sencillo:

nombre, edad: $this->age, "; ) ) clase Hijo extiende Papá // Hijo en americano - hijo, heredero de la clase Papá (padre) ( public $usuario = "Nicer", $contraseña = "secretNic"; función pública printUserInfo() ( echo "iniciar sesión: $this->user, contraseña: $this->contraseña."; ) ) $obj = new Son(); $obj->printInfo(); );

Como puedes ver, solo trabajamos con la instancia de la clase hija Son, pero a través de ella accedemos al método printInfo() de la clase padre Dad. Este es el significado de herencia en PHP.

La palabra extiende se traduce literalmente del inglés como expandir. Entonces, escribir "la clase Hijo extiende a Papá" es muy fácil de entender, a saber: "la clase Hijo extiende (clase) Papá".

Ejemplo de herencia de clases

Terminamos la última lección usando una clase de ejemplo:

identificación = $identificación;

$this->type = "libro";

Herencia en PHP identificación = $identificación;

$this->type = "libro";

$this->name = "Guerra y Paz";

$this->description = "Un libro grueso de varios volúmenes";

$this->precio = "543.26";

) ) clase GoodsInfo extiende Bienes ( función printGoods() ( echo "ID de producto: $this->id. Tipo de producto: $this->tipo. Nombre: \"$this->name\". Descripción: $this-> descripción Precio: $este->precio."; ) ) $Bienes = new GoodsInfo(124); $Bienes->printBienes();

En este ejemplo, la segunda clase GoodsInfo se declara usando la palabra clave extends, lo que significa que es heredera de la clase cuyo nombre se proporciona a continuación, en nuestro caso la clase Goods.

La clase GoodsInfo se llama clase secundaria y la clase Goods se llama clase principal. Estos nombres indican la relación hereditaria de estas clases.

En la clase secundaria GoodsInfo, tenemos acceso a todas las propiedades y métodos de la clase principal.

Dado que la clase GoodsInfo no tiene su propio constructor, el constructor principal se inicia automáticamente. Si la clase secundaria tiene un constructor, entonces el constructor principal no se ejecutará.

Herencia en PHP Escribiré de nuevo: de hecho, una clase secundaria es una extensión de la clase principal. La palabra clave extiende, que indica una relación, se traduce del inglés como extensión.

Es decir, podemos crear una clase que sea un repositorio de información y crear varias clases hijas que procesen esta información, especializándose cada clase en su propia tarea.

Aclarar tipos de objetos

El método printGoods() sólo debería recibir un objeto de la clase Goods como entrada, y nos gustaría comprobarlo. Comprobémoslo así:

Función pública printGoods(Bienes $Bienes) // el método debe recibir un objeto ( echo " ID de producto: $Bienes->id. Tipo de producto: $Bienes->tipo. Nombre: \"$Bienes->nombre\". Descripción : $ Bienes->descripción Precio: $Bienes->precio "; )

La línea printGoods(Goods $Goods) , primero viene el nombre de la clase a la que debe corresponder el objeto argumento, y luego el argumento. Si se pasa al método un argumento de un tipo elemental (cadena, entero, flotante, booleano) o un objeto de otro tipo, se generará un error.

Utilizar esta técnica es muy correcto desde el punto de vista de la seguridad del script.

De esta manera puede verificar los tipos de objetos y las matrices. Aquí está la sintaxis para verificar las matrices:

función pública imprimirBienes(matriz $Bienes) (...)

Y las cadenas y otros tipos elementales deben comprobarse con funciones especiales.

También puede exigir que el argumento sea cierto tipo, o valor cero(NULO).

función pública printGoods(array $Goods=null) (...)

Alcance en PHP

Ahora podemos cerrar el tema del alcance de propiedades y métodos. hay tres palabras clave, para definir diferentes alcances.

  • público: disponible para todos.
  • protegido: disponible para esta clase y sus hijos, así como para sus objetos.
  • Privado: no está disponible ni siquiera para clases infantiles.

Se trata de alcance.

Trabajar con herencia en PHP

Desde una clase secundaria puede llamar a un método en la clase principal. Para ello se utiliza un descriptor (en inglés - parent).

Herencia en PHP identificación = $identificación;

$this->type = "libro";

$this->name = "Guerra y Paz";

$this->description = "Un libro grueso de varios volúmenes";

Herencia en PHP

Primero escribimos el nombre de la clase, luego dos puntos y luego el método.

Reanudar

Entonces, hemos estudiado el mecanismo de herencia. Por supuesto, aún queda mucho por estudiar, esta información es sólo introductoria.

Sigamos con la siguiente lección:

En este tutorial hablaremos sobre la herencia en programación orientada a objetos y cómo funciona en PHP. Al utilizar la herencia, puede hacer que las clases sean mucho más sólidas y flexibles, y también ahorrar mucho tiempo escribiendo guiones.

Veremos lo siguiente:

  • El concepto de herencia y por qué es útil utilizarlo;
  • Cómo una clase PHP puede heredar de otra;
  • Cómo uno de los “hijos” de una clase puede sobrecargar la funcionalidad de sus métodos “padres”;
  • Trabajar con métodos y clases finales;
  • Usando clases abstractas;
  • Trabajar con interfaces.

¿Estás listo? ¡Entonces adelante!

¿Cómo se realiza la herencia?

La herencia se basa en los conceptos de clase principal y clase sucesora. Usando una determinada sintaxis, puede crear una clase que heredará (se convertirá en descendiente de) otra clase.

Nota: Las clases principales también se denominan clases base o superclases. Las clases heredadas, a su vez, pueden denominarse clases hijas o subclases.

Cuando crea una clase hija, hereda todos los campos y métodos de su clase base. Puede agregar campos y métodos adicionales a una clase secundaria, ampliando así la funcionalidad de la clase principal.

Por ejemplo, en una aplicación web de foro hay una clase Miembro, que tiene métodos createPost(), editProfile(), showProfile(), etc. Dado que los administradores del foro también son miembros, puede crear una clase Administrador, un hijo de la Clase de miembro. La clase Administrador hereda todos los campos y métodos de la clase Miembro, lo que significa que un objeto de clase Administrador se comportará exactamente como un objeto Miembro.

Puede ampliar la funcionalidad de la clase Administrador agregando métodos como createForum(), deleteForm() y banMember(). Y si desea asignar roles a administradores, agregue un campo a esta clase secundaria, por ejemplo, $adminLevel.

Al hacer esto, evita saturar la clase Miembro con métodos y campos que no son adecuados para miembros habituales del foro, sino sólo para administradores. Tampoco tendrá que copiar y pegar métodos y campos de la clase Miembro en la clase secundaria. Entonces la herencia es perfecta para ti.

Nota: puedes crear tantas clases hijas como necesites a partir de una única superclase, y puedes agregar más y más métodos y campos a cada una de ellas.

Crear clases secundarias

Entonces, ¿cómo se crea una clase que hereda otra clase en PHP? Hay una palabra clave que se extiende para esto:

Clase ParentClass (//descripción de campos y métodos) clase ChildClass extiende ParentClass (//descripción de campos y métodos adicionales)

Creamos una clase ParentClass y luego una clase ChildClass, que hereda de ParentClass. ChildClass hereda todos los campos y métodos de la clase ParentClass y también puede agregarle sus propios campos y métodos.

Y ahora, un ejemplo. Creemos una clase de Miembro para un foro web imaginario y luego una clase de Administrador, hija de Miembro:

Miembro de clase ( public $nombre de usuario = ""; privado $loggedIn = false; función pública inicio de sesión() ( $this->loggedIn = true; ) función pública cerrar sesión() ( $this->loggedIn = false; ) función pública isLoggedIn( ) ( return $this->loggedIn; ) ) clase Administrador extiende Miembro ( función pública createForum($forumName) ( echo "$this->username creó un nuevo foro: $forumName
"; ) función pública banMember($miembro) ( echo "$this->nombre de usuario prohibió al miembro: $miembro->nombre de usuario
"; } }

Como puede ver, la clase Miembro contiene un campo público $nombre de usuario y un campo privado $loggedIn, así como métodos para iniciar y cerrar sesión en el foro y un método para determinar si el usuario ha iniciado sesión o no.

  • createForum($forumName) para crear un nuevo foro llamado $forumName;
  • banMember($miembro) para prohibir al usuario $miembro.

Nota: naturalmente estos métodos no hacen nada, ya que nuestro foro es imaginario. Simplemente muestran algunos mensajes en la página.

Echemos un vistazo a nuestras clases en acción. Creemos un objeto de ambas clases y luego llamemos a algunos de sus métodos:

// crear un miembro del foro e iniciar sesión $miembro = nuevo miembro(); $miembro->nombre de usuario = "Fred"; $miembro->iniciar sesión(); echo $miembro->nombre de usuario. "es". ($miembro->
"; // crea un administrador e inicia sesión $admin = new Administrator(); $admin->username = "Mary"; $admin->login(); echo $admin->username . " es " . ($ miembro- >isLoggedIn() ? "ha iniciado sesión": "desconectado") "
"; // muestra "Mary creó un nuevo foro: Teddy Bears" $admin->createForum("Teddy Bears"); // muestra "Mary prohibió al miembro: Fred" $admin->banMember($member);

La página mostrará:

Fred ha iniciado sesión Mary ha iniciado sesión Mary creó un nuevo foro: Teddy Bears Mary prohibió al miembro: Fred

Así es como funciona:

  1. Primero, creamos un objeto de la clase Miembro, configuramos el nombre de usuario en "Fred", lo iniciamos y mostramos un mensaje en la página que decía que había iniciado sesión en el foro.
  2. Luego creamos un objeto de la clase Administrador. Dado que esta clase hereda de Miembro, podemos usar todos los métodos y campos de esta clase para objetos de la clase Administrador. Le damos un nombre al administrador, Mary, y la iniciamos, después de lo cual mostramos un mensaje que dice que ha iniciado sesión.
  3. Ahora llamamos al método createForum() de la clase Administrador, pasando el nombre del foro: "Teddy Bears".
  4. Finalmente, llamamos al método banMember() desde el objeto admin, pasando el nombre de usuario Fred.

Ésta es la esencia de la herencia en la programación orientada a objetos. Más adelante en la lección, veremos varias formas de manipular la herencia, incluida la sobrecarga, las clases y métodos finales, las clases abstractas y las interfaces.

Sobrecarga de métodos principales

Como ya has visto, cuando creas una clase hija, hereda todos los campos y métodos de su clase padre. Sin embargo, puede ser necesario cambiar la funcionalidad de los métodos de superclase en una clase secundaria.

Usando el foro como ejemplo: cuando un administrador inicia sesión, sucede exactamente de la misma manera que para un usuario normal, pero es posible que desee escribir los registros en un archivo específico por motivos de seguridad.

Al sobrecargar el método login() en una clase secundaria, puede cambiar este método a su gusto.

Para sobrecargar un método de superclase en una clase secundaria, simplemente cree un método con el mismo nombre. Luego, al llamar a un método para objetos de una clase hija, se llamará al método sobrecargado y no al método de la superclase:

Clase ParentClass (función pública myMethod() ( // (acciones) ) ) clase ChildClass extiende ParentClass (función pública myMethod() ( // llamada a un objeto ChildClass // en lugar del método de superclase MyMethod() ) )

Sobrecarguemos el método login() para la clase Administrador para que los registros se escriban en un archivo:

Miembro de clase ( public $nombre de usuario = ""; privado $loggedIn = false; inicio de sesión de función pública() ( $this->loggedIn = true; ) cierre de sesión de función pública() ( $this->loggedIn = false; ) ) Administrador de clase extiende Miembro ( inicio de sesión de función pública() ( $this->loggedIn = true; echo "Entrada de registro: $this->nombre de usuario conectado
"; ) ) // crea un nuevo usuario e inicia sesión $miembro = nuevo miembro(); $miembro->nombre de usuario = "Fred"; $miembro->login(); $miembro->logout(); // cree un nuevo administrador e inicie sesión $admin = new Administrador(); $admin->nombre de usuario = "Mary" $admin->login() // muestra "Entrada de registro: Mary inició sesión" $admin->logout( );

Como puede ver, sobrecargamos el método login() de la clase Administrador para que muestre mensajes como en archivos de registro.

Luego creamos un usuario normal (Fred) y un administrador (Mary). Llamar al método login() de Fred llama a Member::login(). Y cuando llamamos a un método del administrador Mary, se llamará al método Administrator::login(), ya que PHP ve que hemos sobrecargado este método para esta clase. La página mostrará la línea "Entrada de registro: Mary inició sesión".

Por otro lado, no sobrecargamos el método logout() en la clase secundaria, por lo que se llama a Member:logout() tanto para administradores como para usuarios habituales.

Llamar a un método de superclase desde una clase secundaria

Cuando sobrecargas un método en una clase secundaria, normalmente no necesitas cambiar todo el método. Necesitará utilizar la funcionalidad del método de la superclase y agregar algunas cosas al método de la clase secundaria.

En el ejemplo dado en el último párrafo, sobrecargamos el método login(). Pero duplicamos parte del método Member::login() en Administrator::login():

El administrador de clase extiende el miembro (función pública inicio de sesión() ($this->loggedIn = true; echo "Entrada de registro: $this->nombre de usuario conectado
"; } }

En lugar de duplicar el código, es mejor llamar al método Member::login() desde Administrator::login().

Para acceder a un método de superclase desde una clase secundaria, utilice la palabra clave principal:

Padre::miMétodo();

Ahora reescribamos el método login() en la clase secundaria para que llame al mismo método en la clase principal y luego agreguemos algo nuevo:

Administrador de clase extiende Miembro ( función pública inicio de sesión() ( parent::login(); echo "Entrada de registro: $this->nombre de usuario conectado
"; } }

Esto no sólo acorta el código, sino que también facilita la realización de ajustes futuros. Si luego necesita cambiar la forma en que cualquier usuario inicia sesión, solo necesitará ajustar el método login() en la clase Miembro, y la clase Administrador llamará al método ya modificado.

Prevención de la herencia con métodos y clases finales

En la mayoría de los casos, permitir que las clases amplíen su funcionalidad mediante herencia es una buena práctica. Esto es parte del poder de la programación orientada a objetos.

Sin embargo, sucede que sobrecargar los métodos de las superclases puede provocar problemas, reducir la seguridad y complicar el código. En estos casos, sería útil desactivar la herencia de un método o incluso de una clase completa.

Para evitar que las clases secundarias sobrecarguen los métodos de una superclase, agregue la palabra clave final antes de su declaración. Por ejemplo, es posible que desee evitar que el método login() de la clase Miembro se sobrecargue por razones de seguridad:

Miembro de clase ( público $nombre de usuario = ""; privado $loggedIn = false; función final pública inicio de sesión() ( $this->loggedIn = true; ) función pública cerrar sesión() ( $this->loggedIn = false; ) función pública isLoggedIn () (retorna $this->loggedIn; ) )

Si alguien intenta heredar una clase y sobrecargar este método:

Clase NaughtyMember extiende Miembro (función pública inicio de sesión() ($this->loggedIn = true; // hacer algo malo))

... PHP imprimirá un mensaje de error:

Error grave: no se puede anular el método final Member::login()

También puedes desactivar la herencia de toda la clase:

Miembro final de la clase (//no puedes heredar de esta clase en absoluto)

Cualquier intento de crear una clase hija de esta clase fallará:

Error fatal: la clase NaughtyMember no puede heredar de la clase final (Miembro)

Nota: Aunque se trata más de Java que de PHP, resalta los beneficios de usar métodos y clases finales.

Trabajar con clases abstractas

Una clase abstracta es una clase de la que no se puede crear instancias, es decir, no se puede crear un objeto de la clase si es abstracta. En su lugar, crea clases secundarias a partir de él y crea silenciosamente objetos a partir de esas clases secundarias. Las clases abstractas son plantillas para crear clases.

Una clase abstracta contiene uno o más métodos abstractos. Cuando creas un método abstracto en una clase abstracta, no agregas nada a ese método. En cambio, debe declararse en cualquier clase secundaria.

Nota: Una vez que haya creado al menos un método abstracto en una clase, debe declarar esa clase como abstracta.

Cuando una clase regular hereda de una clase abstracta, debe implementar todos los métodos abstractos de la clase principal. De lo contrario, PHP generará un error. Por tanto, una clase abstracta crea "reglas de comportamiento" para sus clases hijas.

Nota: puede agregar métodos no abstractos a una clase abstracta. Serán heredados por las clases secundarias como de costumbre.

Veamos un ejemplo. Digamos que estamos creando un sitio web que tiene tanto miembros del foro como compradores de una tienda en línea que forma parte de nuestro sitio. Dado que tanto los participantes del foro como los compradores son personas, podemos crear una clase Persona abstracta, que tendrá algunos campos y métodos comunes a todos los usuarios del sitio:

Clase abstracta Persona (privado $primerNombre = ""; privado $apellido = ""; función pública setName($primerNombre, $apellido) ( $this->firstName = $firstName; $this->lastName = $apellido; ) función pública getName() ( return "$this->firstName $this->lastName"; ) función pública abstracta showWelcomeMessage();

Como puede ver, hemos creado una clase abstracta agregando la palabra clave abstracta a su descripción. Esta clase tiene varias propiedades comunes a todas las personas: $frstName y $lastName, así como métodos para inicializar y leer los valores de estos campos.

La clase también tiene un método abstracto showWelcomeMessage(). Este método muestra un saludo cuando el usuario ingresa al sitio. Nuevamente, agregamos la palabra clave abstracta a la descripción de este método para hacerlo abstracto. Como es abstracto, no contiene una sola línea de código, es solo una declaración del mismo. Sin embargo, cualquier clase secundaria debe agregar y definir un método showWelcomeMessage().

Ahora creemos un par de clases a partir de la clase abstracta Persona:

  1. Clase de miembro para miembros del foro;
  2. Clase de comprador para compradores de tiendas online.

Miembro de clase extiende Persona ( función pública showWelcomeMessage() ( echo "Hola " . $this->getName() . ", ¡bienvenido a los foros!
"; ) función pública nuevoTema($asunto) ( echo "Creando nuevo tema: $asunto
"; ) ) clase Shopper extiende Persona ( función pública showWelcomeMessage() ( echo "Hola " . $this->getName() . ", ¡bienvenido a nuestra tienda en línea!
"; ) función pública addToCart($artículo) ( echo "Añadiendo $artículo al carrito
"; } }

Como puede ver, cada uno de ellos describe el método showWelcomeMessage() de una superclase abstracta. Se implementan de manera diferente: la clase Miembro muestra el mensaje "bienvenido a los foros" y la clase Comprador muestra "bienvenido a nuestra tienda en línea", pero esto es normal. Lo principal es que ambos describieron este método.

Si uno de ellos, como Shopper, no describiera el método, PHP arrojaría un error:

Además de implementar un método abstracto, cada clase tiene sus propios métodos regulares. El miembro tiene un método newTopic() para crear un nuevo tema en el foro y el comprador tiene un método addToCart() para agregar artículos al carrito.

Ahora podemos crear miembros del foro y compradores en nuestro sitio. Podemos llamar a los métodos newTopic() y addToCart() en estos objetos, así como a getName() y setName(), ya que heredan de la superclase Persona.

Además, sabiendo que las clases Member y Shopper heredan de Person, podemos llamar con seguridad al método showWelcomeMessage() en ambas clases, ya que está exactamente implementado en ambas. Estamos seguros de esto porque sabemos que fue declarado como un método abstracto en la clase Persona.

He aquí un ejemplo:

$aMiembro = nuevo Miembro(); $aMiembro->setName("Juan", "Smith"); $aMiembro->mostrarMensaje de Bienvenida(); $aMember->newTopic("Los ositos de peluche son geniales"); $aComprador = nuevo Comprador(); $aComprador->setName("María", "Jones"); $aComprador->mostrarMensaje de Bienvenida(); $aShopper->addToCart("Lámpara de mesa adornada");

La página mostrará:

Hola John Smith, ¡bienvenido a los foros! Creando un tema nuevo: Los ositos de peluche son geniales Hola Mary Jones, ¡bienvenida a nuestra tienda en línea! Agregar lámpara de mesa ornamentada al carrito

Crear y usar interfaces

Las interfaces son similares a las clases abstractas en muchos aspectos. Una interfaz es una plantilla que define el comportamiento de una o más clases.

Estas son las principales diferencias entre interfaces y clases abstractas:

  1. Ningún método puede describirse en una interfaz. Todos ellos son abstractos. Una clase abstracta puede tener métodos no abstractos.
  2. Una interfaz no puede contener campos, sólo métodos.
  3. Una clase implementa una interfaz y una clase hereda o extiende otra clase.
  4. Una clase puede implementar varias interfaces al mismo tiempo. Una misma clase puede heredar de otra clase. Pero una clase secundaria sólo puede tener una superclase (abstracta o no).

Al igual que una clase abstracta, una interfaz declara varios métodos que deben implementarse en cualquier clase que implemente la interfaz. La sintaxis se ve así:

Interfaz MiInterfaz (función pública unmétodo(); función pública otrométodo(); )

Para crear una clase que implemente una interfaz particular, escriba esto:

Clase MyClass implementa MyInterface ( función pública aMethod() ( // (implementación del método) ) función pública otroMetodo() ( // (implementación del método) ) )

Las interfaces son útiles cuando necesitas crear varias clases no relacionadas que comparten una funcionalidad común.

Por ejemplo, un foro web puede contener una clase Miembro para los miembros del foro y una clase Tema para los temas creados por los miembros del foro. En términos de herencia, lo más probable es que estas clases no dependan entre sí, ya que realizan funciones completamente diferentes.

Sin embargo, supongamos que necesitaremos recuperarlos y escribir objetos Miembro y Tema en la base de datos. Para hacer esto, crearemos una interfaz Persistable, que tendrá métodos para guardar objetos en la base de datos y recuperarlos desde allí:

Interfaz persistente (función pública guardar(); función pública cargar(); función pública eliminar(); )

Ahora creemos una clase Miembro e implementemos la interfaz Persistente para ella. Esto significa que la interfaz debe tener los métodos save(), load() y delete():

El miembro de la clase implementa Persistente (privado $nombre de usuario; privado $ubicación; privado $página de inicio; función pública __construct($nombre de usuario, $ubicación, $página de inicio) ( $this->nombre de usuario = $nombre de usuario; $this->ubicación = $ubicación; $ this->homepage = $homepage; ) función pública getUsername() ( return $this->username; ) public function getLocation() ( return $this->ubicación; ) public function getHomepage() ( return $this->homepage; ) función pública save() ( echo "Guardando miembro en la base de datos
"; ) función pública cargar() ( echo "Cargando miembro desde la base de datos
"; ) función pública eliminar () ( echo "Eliminar miembro de la base de datos
"; } }

Nuestra clase Topic también implementará esta interfaz, por lo que también debería tener estos tres métodos:

El tema de clase implementa Persistable ( $asunto privado; $autor privado; $createdTime privado; función pública __construct($asunto, $autor) ( $this->asunto = $asunto; $this->autor = $autor; $this-> createTime = time(); función pública showHeader() ( $createdTimeString = date("l jS M Y h:i:s A", $this->createdTime); $authorName = $this->author->getUsername() ; echo "$this->asunto (creado en $createdTimeString por $authorName)
"; ) función pública guardar() ( echo "Guardando tema en la base de datos
"; ) función pública cargar() ( echo "Cargando tema desde la base de datos
"; ) función pública eliminar () ( echo "Eliminar tema de la base de datos
"; } }

Nota: dado que nuestro foro es imaginario, en lugar de interactuar con la base de datos, los métodos save(), load() y delete() simplemente muestran mensajes.

Ahora podemos crear objetos de las clases Miembro y Tema, y ​​luego llamar a sus métodos getUsername() y showHeader(). Además, sabiendo que estas clases implementan la interfaz Persistable, podemos llamar a métodos como save(), load() o delete():

$aMiembro = nuevo Miembro("fred", "Chicago", "http://example.com/"); echo $aMiembro->getUsername() . "vive en" $aMiembro->getLocation() ".
"; $aMiembro->save(); $aTopic = new Topic("Los osos de peluche son geniales", $aMiembro); $aTopic->showHeader(); $aTopic->save();

La página mostrará:

Fred vive en Chicago Guardando miembro en la base de datos Teddy Bears are Great (creado el miércoles 25 de mayo de 2011 02:19:14 a. m. por fred) Guardando tema en la base de datos

Como puede ver, las interfaces pueden conectar clases que no tienen nada que ver entre sí para ciertos propósitos, como escribir en una base de datos de objetos de clase. No olvides que una clase puede implementar varias interfaces:

Clase MyClass implementa una Interfaz, otra Interfaz (...)

Nota: Las interfaces son una característica poderosa de la programación orientada a objetos y hay mucho más que decir sobre ellas. Puede obtener más información sobre ellos en la documentación de PHP.

Conclusión

En esta lección, aprendió sobre una de las propiedades más poderosas de la programación orientada a objetos: la herencia. Aprendiste:

  1. Cómo funciona la herencia y cómo utilizarla para ampliar clases;
  2. Cómo crear clases hijas en PHP;
  3. Por qué es posible que desee sobrecargar métodos en clases secundarias;
  4. Cómo acceder a los métodos de superclase;
  5. Todo sobre los métodos y clases finales, y por qué es útil utilizarlos;
  6. El concepto de clases abstractas para crear plantillas de clases secundarias;
  7. Cómo utilizar interfaces para proporcionar funcionalidad común a clases no relacionadas.

Si ha completado todas las lecciones de esta serie, ya podrá escribir aplicaciones complejas en programación orientada a objetos. ¡Felicidades!

En el siguiente y último tutorial, te mostraré algunas características de programación orientada a objetos súper útiles que tiene PHP.

Hasta entonces, ¡feliz codificación!

Cuando se trabaja con clases en PHP, a menudo es necesario ampliar la funcionalidad del código. Pero si no es posible cambiar la clase original, se puede ampliar fácilmente creando una "copia".

Las clases que amplían el original se llaman " subsidiarias", y el padre es " superclase". Una superclase puede tener muchas clases secundarias.

se extiende

Veamos los principios básicos de la herencia de clases:

  • Usando la herencia, podemos crear clases que contendrán todas las propiedades y métodos de la clase principal, es decir. las clases secundarias heredan público Y protegido propiedades y métodos de la clase padre.
  • Una clase hija es una extensión de la clase padre, ya que además de propiedades y métodos heredados, puede contener los suyos propios.
  • La herencia se establece mediante el uso de la palabra. se extiende al crear una clase.
  • Si el heredero no tiene su propio constructor (escribí sobre esto antes), entonces el constructor del padre se iniciará automáticamente. Si la clase secundaria tiene un constructor, entonces el constructor principal no se ejecutará.
  • Las clases secundarias pueden anular propiedades y métodos de la superclase. Al definir una subclase, nos aseguramos de que su instancia esté definida por las características primero de la clase secundaria y luego de la clase principal.

Veamos un ejemplo sencillo. tengamos clase Ploshad, que calcula la superficie. Pero ahora necesitábamos calcular su volumen. La clase original no se puede cambiar. Creemos una clase infantil. Obyem, que heredará todas las propiedades y métodos Ploshad y agregue funcionalidad para calcular el volumen:

clase cuadrada (
ancho $ protegido;
altura $ protegida;
función pública __construct($x, $y) (
$esto->ancho = $x;
$this->altura = $y; )
función pública Cuadrado() ( return $this->width * $this->height; )
}

la clase Obyem extiende Ploshad (
protegido $glibina;
función pública Obyemss($g) (
$this->glybina = $g;
return $this->Cuadrado()* $this->glybina;
}
}

Al grabar clase Obyem extiende Ploshad declaramos que la clase Obyem hereda las propiedades y métodos de la clase Ploshad y puede controlarlos. Adentro Obyem hemos registrado una nueva propiedad $glibina y metodo función pública Obyemss($g). Ahora calculemos el volumen y el área:

$obj = nuevo Obyem(2,12); //crea un objeto a partir del heredero
echo "Área: ".$obj->Cuadrado(); // antigua función principal
echo "Volumen: ".$obj->Obyemss(2); //nueva función heredera

Como puede ver en los comentarios, $obj ahora puede usar tanto los métodos antiguos de la clase Ploshad como los nuevos métodos de la clase secundaria Obyem.

Al calcular el área, el intérprete de PHP busca un constructor en la clase Obyem; si no lo encuentra, ejecuta el constructor en Ploshad. Anula los valores de las propiedades pasadas (Obyem(2,12)). Luego, el método Square() se ejecuta y utiliza estos datos.

En el caso del volumen, también se lanza el constructor en Ploshad, y luego el método Obyemss($g), en el que se pasa la altura. Dentro del método, utilizamos el cálculo del área multiplicado por la altura y obtenemos el resultado.

La herencia se utiliza cuando la funcionalidad dentro de una clase se vuelve demasiado compleja para comprenderla y trabajar con ella, así como para crear excepciones o distinguir entre tipos de datos. Por ejemplo, tiene una clase para descargar productos de libros con muchos campos (autor, año de publicación, número de páginas). Ahora, si necesita mostrar un producto de un tipo diferente, por ejemplo: juegos en DVD, entonces tendrá otros parámetros (requisitos del sistema). Por lo tanto, si una clase comienza a parecerse a dos clases, es mejor heredar.

El intérprete de PHP siempre mira primero la clase secundaria:

  1. ¿Existe un constructor? Si lo hay, ignora el constructor del padre.
  2. ¿Existen propiedades y métodos? Si coinciden en el niño y el padre, entonces se utilizan los niños. Por lo tanto, puede reescribir completamente la funcionalidad de los métodos de la clase principal.

extiende padre::

padre::- se utiliza si es necesario cambiar la funcionalidad del método principal en una clase secundaria

Ejemplo:
clase PloshadProcent extiende Ploshad (
función Cuadrado() (
$cadena = padre::Cuadrado();
$cadena = $cadena*0.1;
devolver $cadena;
}
}

Ahora cuando nos llamen, recibiremos el 10% de nuestra área:
$obj2 = nuevo PloshadProcent(2,12);
echo "Área 10%: ".$obj2->Cuadrado(); //dará 2.4

Hemos anulado el método de superclase Square() dentro de PloshadProcent

La segunda y muy importante forma de utilizar parent:: es anular la funcionalidad del constructor dentro de una clase secundaria. Esto se puede utilizar si la superclase no tiene ninguna propiedad nueva con la que trabajar:

Sea una clase de libro y su constructor toma solo 2 parámetros: $título, $precio.

libro de clase (
título $ público;
precio público $;
función __construct($título, $precio) (
$this->título = $título;
$this->precio = $precio;
}
}

De repente necesitábamos mostrar un nuevo parámetro $pages. Creemos una instancia de la clase new_book y creemos en ella nuestro propio constructor, que ya contendrá los datos necesarios: $title, $price, $pages

Cuando una clase secundaria define su propio constructor, PHP no llama automáticamente al constructor de la clase principal. Esto debe hacerse manualmente en el constructor de la subclase.

La clase hija en su constructor llama al constructor de su clase padre, le pasa los argumentos necesarios para la inicialización, lo ejecuta y luego se ejecuta el código que implementa una funcionalidad adicional, en este caso inicializando una propiedad de la subclase.

clase nuevo_libro extiende libro (
$páginas públicas;
función __construct($título, $precio, $páginas) (
padre::__construct($título, $precio); // llama al método constructor de la clase padre
$this->páginas = $páginas; // inicializa la propiedad definida en la subclase
}
}
$obj = nuevo nuevo_libro("ABC", 35, 500);
echo "Libro: $obj->título | Precio: $obj->precio | Páginas: $obj->páginas";

De esta manera, podemos ampliar la funcionalidad de las superclases sin cambiarlas. En la próxima lección aprenderás




Arriba