tutorial - ¿Cuál es el punto de las interfaces en PHP?
para que sirven las interfaces en php (14)
Interfaces permiten crear código que define los métodos de las clases que lo implementan. Sin embargo, no puede agregar ningún código a esos métodos.
Las clases abstractas le permiten hacer lo mismo, además de agregar código al método.
Ahora, si puede lograr el mismo objetivo con clases abstractas, ¿por qué necesitamos el concepto de interfaces?
Me han dicho que tiene que ver con la teoría OO de C ++ a Java, que es en lo que se basa el OO de PHP. ¿Es el concepto útil en Java pero no en PHP? ¿Es solo una manera de evitar tener marcadores de posición en la clase abstracta? ¿Me estoy perdiendo de algo?
No puedo recordar si PHP es diferente a este respecto, pero en Java, puede implementar múltiples Interfaces, pero no puede heredar múltiples clases abstractas. Asumiría que PHP funciona de la misma manera.
En PHP puede aplicar varias interfaces separándolas con una coma (creo que no encuentro una solución limpia).
En cuanto a las clases abstractas múltiples, podría tener varios resúmenes que se extiendan entre sí (de nuevo, no estoy totalmente seguro de eso, pero creo que ya lo he visto en alguna parte) Lo único que no puedes extender es una clase final.
A continuación se muestran los puntos para la interfaz de PHP
- Se utiliza para definir el no requerido de los métodos de la clase [si desea cargar html, se requieren el ID y el nombre, por lo que en este caso la interfaz incluye setID y setName].
- La interfaz obliga a la clase a incluir todos los métodos definidos en ella.
- Solo se puede definir método en interfaz con accesibilidad pública.
- También puede ampliar la interfaz como clase. Puede ampliar la interfaz en PHP utilizando la palabra clave se extiende.
- Extender la interfaz múltiple.
- No puede implementar 2 interfaces si ambas comparten una función con el mismo nombre. Lanzará error.
Código de ejemplo:
interface test{
public function A($i);
public function B($j = 20);
}
class xyz implements test{
public function A($a){
echo "CLASS A Value is ".$a;
}
public function B($b){
echo "CLASS B Value is ".$b;
}
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);
El concepto es útil para la programación orientada a objetos. Para mí pienso en una interfaz como un contrato. Mientras mi clase y su clase estén de acuerdo con este contrato de firma de método, podemos "interconectar". En cuanto a las clases abstractas, las que veo son más de clases base que ocultan algunos métodos y necesito completar los detalles.
En mi opinión, las interfaces deberían preferirse a las clases abstractas no funcionales. No me sorprendería si hubiera un impacto en el rendimiento allí, ya que solo hay un objeto instanciado, en lugar de analizar dos, combinándolos (aunque, no estoy seguro, no estoy familiarizado con el funcionamiento interno de PHP OOP).
Es cierto que las interfaces son menos útiles / significativas en comparación con, digamos, Java. Por otro lado, PHP6 introducirá aún más sugerencias de tipo, incluyendo sugerencias de tipo para valores de retorno. Esto debería agregar algún valor a las interfaces de PHP.
tl; dr: interfaces define una lista de métodos que deben seguirse (piense en la API), mientras que una clase abstracta proporciona cierta funcionalidad básica / común, que las subclases refinan según las necesidades específicas.
Interfaces no le dará a su código ningún aumento de rendimiento ni nada por el estilo, pero pueden hacer mucho para que se pueda mantener. Es cierto que se puede usar una clase abstracta (o incluso una clase no abstracta) para establecer una interfaz para su código, pero las interfaces adecuadas (las que usted define con la palabra clave y que solo contienen firmas de métodos) son mucho más fáciles de usar. ordenar y leer.
Dicho esto, tiendo a usar la discreción cuando decido si usar o no una interfaz en una clase. Algunas veces quiero implementaciones de métodos predeterminados, o variables que serán comunes a todas las subclases.
Por supuesto, el punto sobre la implementación de múltiples interfaces también es acertado. Si tiene una clase que implementa múltiples interfaces, puede usar un objeto de esa clase como tipos diferentes en la misma aplicación.
Sin embargo, el hecho de que tu pregunta sea sobre PHP hace que las cosas sean un poco más interesantes. Escribir en interfaces aún no es increíblemente necesario en PHP, donde puedes alimentar cualquier cosa a cualquier método, independientemente de su tipo. Puede escribir estáticamente los parámetros del método, pero parte de eso está roto (String, creo, causa algunos contratiempos). Combine esto con el hecho de que no puede escribir la mayoría de las demás referencias, y no tiene mucho valor tratar de forzar la escritura estática en PHP ( en este punto ). Y debido a eso, el valor de las interfaces en PHP , en este punto es mucho menor de lo que lo es en lenguajes más fuertemente tipados. Tienen el beneficio de la legibilidad, pero poco más. La implementación múltiple ni siquiera es beneficiosa, porque aún tiene que declarar los métodos y darles cuerpos dentro del implementador.
La diferencia entre usar una interfaz y una clase abstracta tiene más que ver con la organización del código para mí, que con la aplicación del propio lenguaje. Los uso mucho cuando preparo el código para que otros desarrolladores trabajen para que se mantengan dentro de los patrones de diseño previstos. Las interfaces son un tipo de "diseño por contrato" en el que su código acepta responder a un conjunto prescrito de llamadas a la API que pueden provenir de un código para el que no tiene acceso.
Si bien la herencia de la clase abstracta es una relación "es una", eso no siempre es lo que se quiere, y la implementación de una interfaz es más una relación "actúa como una". Esta diferencia puede ser bastante significativa en ciertos contextos.
Por ejemplo, supongamos que tiene una Cuenta de clase abstracta de la que se extienden muchas otras clases (tipos de cuentas, etc.). Tiene un conjunto particular de métodos que solo son aplicables a ese grupo de tipos. Sin embargo, algunas de estas subclases de cuenta implementan Versionable, Listable o Editable para que puedan lanzarse a los controladores que esperan usar esas API. Al controlador no le importa qué tipo de objeto es
Por el contrario, también puedo crear un objeto que no se extienda desde Cuenta, digamos una clase abstracta de Usuario y aún implementar Listable y Editable, pero no Versionable, que no tiene sentido aquí.
De esta manera, estoy diciendo que la subclase FooUser NO es una cuenta, pero SÍ actúa como un objeto editable. Del mismo modo, BarAccount se extiende desde Cuenta, pero no es una subclase de Usuario, sino que implementa Editable, Listable y Versionable.
Agregar todas estas API para Editable, Listable y Versionable en las clases abstractas no solo sería abarrotado y feo, sino que duplicaría las interfaces comunes en Cuenta y Usuario, o forzaría a mi objeto Usuario a implementar Versionable, probablemente solo para lanzar un excepción.
Las interfaces no existen como una base sobre la cual se pueden extender las clases, sino como un mapa de las funciones requeridas.
El siguiente es un ejemplo del uso de una interfaz donde no cabe una clase abstracta:
Digamos que tengo una aplicación de calendario que permite a los usuarios importar datos de calendario de fuentes externas. Escribiría clases para manejar la importación de cada tipo de origen de datos (ical, rss, atom, json). Cada una de esas clases implementaría una interfaz común que aseguraría que todos tengan los métodos públicos comunes que mi aplicación necesita para obtener los datos.
<?php
interface ImportableFeed
{
public function getEvents();
}
Luego, cuando un usuario agrega un nuevo feed, puedo identificar el tipo de feed y usar la clase desarrollada para ese tipo para importar los datos. Cada clase escrita para importar datos para una fuente específica tendría un código completamente diferente, de lo contrario, podría haber muy pocas similitudes entre las clases fuera del hecho de que se requiere que implementen la interfaz que permite que mi aplicación las consuma. Si utilizara una clase abstracta, podría ignorar muy fácilmente el hecho de que no he anulado el método getEvents () que luego rompería mi aplicación en este caso, mientras que usar una interfaz no permitiría que mi aplicación se ejecute si CUALQUIERA de los métodos Los definidos en la interfaz no existen en la clase que la implementó. Mi aplicación no tiene que preocuparse por la clase que usa para obtener datos de una fuente, solo que los métodos que necesita para obtener esos datos están presentes.
Para llevar esto un paso más allá, la interfaz resulta extremadamente útil cuando vuelvo a mi aplicación de calendario con la intención de agregar otro tipo de feed. El uso de la interfaz ImportableFeed significa que puedo continuar agregando más clases que importan diferentes tipos de fuentes simplemente agregando nuevas clases que implementan esta interfaz. Esto me permite agregar toneladas de funcionalidad sin tener que agregar una cantidad innecesariamente masiva a mi aplicación principal, ya que mi aplicación principal solo se basa en que existen los métodos públicos disponibles que la interfaz requiere, siempre que mis nuevas clases de importación de feeds implementen la interfaz ImportableFeed. Sé que puedo dejarlo en su lugar y seguir moviéndome.
Este es solo un comienzo muy simple. Luego puedo crear otra interfaz que todas mis clases de calendario pueden requerir para implementar que ofrezca más funcionalidad específica para el tipo de fuente que manejan las clases. Otro buen ejemplo sería un método para verificar el tipo de feed, etc.
Esto va más allá de la pregunta, pero desde que usé el ejemplo anterior: las interfaces vienen con su propio conjunto de problemas si se usan de esta manera. Necesito asegurar el resultado que se devuelve de los métodos implementados para coincidir con la interfaz y para lograrlo, uso un IDE que lee bloques PHPDoc y agrego el tipo de retorno como una sugerencia de tipo en un bloque PHPDoc de la interfaz que luego Traducir a la clase concreta que lo implementa. Mis clases que consumen la salida de datos de las clases que implementan esta interfaz, al menos sabrán que está esperando una matriz devuelta en este ejemplo:
<?php
interface ImportableFeed
{
/**
* @return array
*/
public function getEvents();
}
No hay mucho espacio para comparar clases abstractas e interfaces. Las interfaces son simplemente mapas que cuando se implementan requieren que la clase tenga un conjunto de interfaces públicas.
Las interfaces no son solo para asegurarse de que los desarrolladores implementen ciertos métodos. La idea es que debido a que se garantiza que estas clases tienen ciertos métodos, puede usar estos métodos incluso si no conoce el tipo real de la clase. Ejemplo:
interface Readable {
String read();
}
List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
System.out.println(reader.read());
En muchos casos, no tiene sentido proporcionar una clase base, abstracta o no, porque las implementaciones varían enormemente y no comparten nada en común además de algunos métodos.
Los idiomas tipeados dinámicamente tienen la noción de "tipificación de pato" donde no se necesitan interfaces; tiene la libertad de asumir que el objeto tiene el método que está solicitando. Esto soluciona el problema en idiomas tipificados estáticamente donde su objeto tiene algún método (en mi ejemplo, read ()), pero no implementa la interfaz.
Las interfaces son como tus genes.
Las clases abstractas son como tus padres reales.
Sus propósitos son hereditarios, pero en el caso de las clases abstractas frente a las interfaces, lo que se hereda es más específico.
Las interfaces son esencialmente un modelo para lo que puedes crear. Definen qué métodos debe tener una clase, pero puede crear métodos adicionales fuera de esas limitaciones.
No estoy seguro de lo que quieres decir con no poder agregar código a los métodos, porque puedes hacerlo. ¿Está aplicando la interfaz a una clase abstracta o la clase que la extiende?
Un método en la interfaz aplicada a la clase abstracta deberá implementarse en esa clase abstracta. Sin embargo, aplique esa interfaz a la clase extendida y el método solo necesita implementarse en la clase extendida. Podría estar equivocado aquí: no uso interfaces tan a menudo como podría / debería.
Siempre he pensado en las interfaces como un patrón para desarrolladores externos o un conjunto de reglas adicional para garantizar que todo sea correcto.
Todo el punto de las interfaces es brindarle la flexibilidad de forzar a su clase a implementar múltiples interfaces, pero aún así no permitir la herencia múltiple. Los problemas con la herencia de varias clases son muchos y variados, y la página de wikipedia en ellos los resume bastante bien.
Las interfaces son un compromiso. La mayoría de los problemas con la herencia múltiple no se aplican a las clases base abstractas, por lo que la mayoría de los lenguajes modernos en estos días deshabilitan la herencia múltiple, pero llaman a las interfaces de las clases base abstractas y permiten que una clase "implemente" tantos como quieran.
Utilizará interfaces en PHP:
- Para ocultar la implementación: establezca un protocolo de acceso a una clase de objetos y cambie la implementación subyacente sin refactorizar en todos los lugares donde ha usado esos objetos
- Para verificar el tipo, como para asegurarse de que un parámetro tenga un tipo específico
$object instanceof MyInterface
- Para hacer cumplir la comprobación de parámetros en tiempo de ejecución
- Para implementar múltiples comportamientos en una sola clase (construir tipos complejos)
clase Automóvil implementa EngineInterface, BodyInterface, SteeringInterface {
Car
ca ahora start()
, stop()
(EngineInterface) o goRight()
, goLeft()
(interfaz de Steering) y otras cosas que no puedo pensar en este momento
Número 4 es probablemente el caso de uso más obvio que no puede abordar con clases abstractas.
De Pensar en Java:
Una interfaz dice: "Así se verán todas las clases que implementan esta interfaz en particular". Por lo tanto, cualquier código que use una interfaz en particular sabe a qué métodos se puede llamar para esa interfaz, y eso es todo. Así que la interfaz se utiliza para establecer un "protocolo" entre clases.
Vimos que las clases abstractas y las interfaces son similares, ya que proporcionan métodos abstractos que deben implementarse en las clases secundarias. Sin embargo, todavía tienen las siguientes diferencias:
1. Las interfaces pueden incluir métodos abstractos y constantes, pero no pueden contener métodos y variables concretos.
2.Todos los métodos en la interfaz deben estar en el ámbito de visibilidad pública .
3. Una clase puede implementar más de una interfaz, mientras que puede heredar de una sola clase abstracta.
interface abstract class
the code - abstract methods - abstract methods
- constants - constants
- concrete methods
- concrete variables
access modifiers
- public - public
- protected
- private
etc.
number of parents The same class can implement
more than 1 interface The child class can
inherit only from 1 abstract class
Espero que esto ayude a cualquiera a entender!
¿Por qué necesitarías una interfaz, si ya hay clases abstractas? Para prevenir la herencia múltiple (puede causar múltiples problemas conocidos).
Uno de esos problemas:
El "problema del diamante" (a veces denominado "diamante mortal de la muerte") es una ambigüedad que surge cuando dos clases B y C heredan de A y la clase D hereda de B y C. Si hay un método en A que B y C se han anulado, y D no lo ha anulado, entonces ¿qué versión del método hereda D: la de B o la de C?
Fuente: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
¿Por qué / cuándo usar una interfaz? Un ejemplo ... Todos los autos en el mundo tienen la misma interfaz (métodos) ... AccelerationPedalIsOnTheRight()
, BrakePedalISOnTheLeft()
. Imagine que cada marca de automóvil tendría estos "métodos" diferentes de otra marca. BMW tendría Los frenos en el lado derecho y Honda tendría los frenos en el lado izquierdo de la rueda. Las personas tendrían que aprender cómo funcionan estos "métodos" cada vez que compran una marca diferente de automóvil. Por eso es una buena idea tener la misma interfaz en múltiples "lugares".
¿Qué hace una interfaz por ti (por qué alguien usaría una)? Una interfaz le impide cometer "errores" (le asegura que todas las clases que implementen una interfaz específica tendrán todos los métodos que se encuentran en la interfaz).
// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{
public function Create($personObject);
}
class MySqlPerson implements IPersonService
{
public function Create($personObject)
{
// Create a new person in MySql database.
}
}
class MongoPerson implements IPersonService
{
public function Create($personObject)
{
// Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn''t care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
}
}
De esta manera, el método Create()
siempre se usará de la misma manera. No importa si estamos usando la clase MySqlPerson
o la clase MongoPerson
. La forma en que estamos utilizando un método sigue siendo la misma (la interfaz sigue siendo la misma).
Por ejemplo, se usará de esta manera (en todas partes en nuestro código):
new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);
De esta manera, algo como esto no puede suceder:
new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);
Es mucho más fácil recordar una interfaz y usar la misma en todas partes, que en varias diferentes.
De esta manera, el interior del método Create()
puede ser diferente para diferentes clases, sin afectar el código "externo", que llama a este método. Todo lo que el código externo debe saber es que el método Create()
tiene 1 parámetro ( $personObject
), porque así es como el código externo usará / llamará al método. Al código externo no le importa lo que esté sucediendo dentro del método; solo tiene que saber usarlo / llamarlo.
También puede hacer esto sin una interfaz, pero si usa una interfaz, es "más seguro" (porque le impide cometer errores). La interfaz le asegura que el método Create()
tendrá la misma firma (el mismo tipo y el mismo número de parámetros) en todas las clases que implementan la interfaz. De esta manera, puede estar seguro de que CUALQUIER clase que implemente la interfaz IPersonService
, tendrá el método Create()
(en este ejemplo) y necesitará solo un parámetro ( $personObject
) para ser llamado / usado.
Una clase que implementa una interfaz debe implementar todos los métodos, que la interfaz tiene / tiene.
Espero no haberme repetido demasiado.