2010-12-07 14 views
8

Si defino una interfaz en PHP, y una clase de fábrica que crea una instancia de esa interfaz, ¿hay alguna manera de forzar al código del cliente a usar solo la interfaz y no la clase concreta subyacente? Desde mi entendimiento, los clientes también pueden usar cualquier función/campo público en la clase subyacente.¿Cuál es el propósito de las interfaces en php?

Aquí se muestra un ejemplo:

<?php 
interface IMyInterface 
{ 
    public function doSomething(); 
} 
?> 

<?php 
class ConcreteImplOfMyInterface implements IMyInterface 
{ 
    const NotPartOfInterface = 'youcantseeme'; 

    public function doSomething() 
    { 
    } 
} 
?> 

<?php 
class MyInterfaceFactory 
{ 
    public static function createMyInterface() 
    { 
     return new ConcreteImplOfMyInterface(); 
    } 
} 
?> 

<?php 
function client() 
{ 
    $myInterface = MyInterfaceFactory::createMyInterface(); 
    return $myInterface::NotPartOfInterface; 
} 
?> 

Respuesta

6

Lo que está pidiendo solo es posible con un lenguaje estáticamente tipado, y dado que PHP se tipea dinámicamente, la respuesta corta es que no es posible.

Por ejemplo, en Java, createMyInterface podría devolver IMyInterface, y las únicas operaciones posibles en este objeto son las definidas en la propia interfaz. Por supuesto, el objeto es realmente del tipo ConcreteImplOfMyInterface, por lo que siempre puede convertirlo a ese tipo para acceder a los otros campos/métodos.

PHP no tiene tipos declarados, por lo que lo que devuelve de una función es simplemente una "variable" - no tiene ningún tipo. Y como no hay tipos, todas las búsquedas de campos/métodos son dinámicas, de modo que cualquier elemento que esté "allí" en el objeto siempre se puede acceder.

En cierto modo, las interfaces son de hecho un tanto limitadas en el uso en un lenguaje como PHP: cualquier clase que implemente una interfaz debe implementar todos sus métodos, pero no hay garantía de lo que una función puede devolver en el primer lugar, esencialmente no hay garantía de nada en absoluto. Lo mejor que puede hacer es usar instanceof para verificar si una variable desconocida implementa una interfaz determinada.

1

Hacer los métodos privada.

return $myInterface.NotPartOfInterface; 

¿Eso funciona? No creo que debería. Creo que quieres el operador ::.

. solo se utiliza para concatenar cadenas.

9

Esta es la razón por las interfaces son buenos en PHP:

interface Printable{ 
    public function display(); 
} 

function display(Printable $obj){ 
    $obj->display(); 
} 

Requiere que cualquier variable de entrar en esa función sea una instancia de imprimir. Por lo tanto, obliga a cualquiera que use su código a implementar esa interfaz si desea usar esa función.

PHP 5.1 http://php.net/manual/en/language.oop5.typehinting.php

Si desea asegurarse de que otra persona no es capaz de utilizar métodos o variables de una clase específica, es necesario definir los métodos y variables como private. Esto hará que no puedan ser utilizados por otra cosa que no sea esa clase específica. (Ni siquiera las clases que amplían su clase pueden usarlas)

+0

+1 para cosas buenas – alex

+0

Entiendo los modificadores de acceso OOP y sé que PHP tiene tipo de alusión. Sin embargo, el hecho de que no tenga insinuaciones de tipo en los tipos de devolución de funciones hace que las interfaces parezcan algo sin sentido para mí. ¿Qué pasaría si quisiera que las clases en el mismo componente lógico puedan invocar métodos públicos entre sí, pero quería que ese componente como un todo exponga las interfaces públicas que eran la única forma de comunicarse con ese componente? No parece posible en PHP. – jameswelle

+0

Una cosa interesante es que puedes acceder a métodos/variables protegidos e incluso privados de instancias de la clase actual. Por ejemplo, si la clase User tiene propiedad privada $ token, puede tener un método dentro de la clase User como este: public function changeToken (User $ user) {$ user-> token = '1234'; } – Joe

2

Dado que PHP es un lenguaje dinámico, significa que todos los accesos a los miembros de la clase, etc. se resolverán en el tiempo de ejecución. Lo que significa que si tengo un código que llama a $ foo-> bar() y obtuve un objeto en $ foo que tiene el método llamado bar(), se llamaría aunque no sea la barra de métodos() a la que quería llamar pero algún otro método en algún otro objeto que por coincidencia se llama igual.

Sin embargo, dicho esto, puede proporcionar cierta protección mediante el uso de parámetros de teclear para tener una función aceptar sólo los objetos específicos:

function doingSomething(IMyInterface $foo) { 
    $foo->doSomething(); 
} 

Sin embargo, todavía no se puede prohibir a nadie de la implementación de IMyInterface y luego escribir funciones que acepta IMyInterface pero úsalo como si fuera objeto de una clase superior. Como dije, esto se debe a que PHP es un lenguaje dinámico.

Cuestiones relacionadas