ACTUALIZACIÓN : PHP 7.4 ahora admite covarianza y contravarianza, lo que aborda el problema principal planteado en esta pregunta.
Me he encontrado con un problema con el uso de la sugerencia de tipo de retorno en PHP 7. Tengo entendido que la sugerencia : self
significa que tiene la intención de que una clase de implementación regrese a sí misma. Por lo tanto, usé : self
en mis interfaces para indicar eso, pero cuando intenté implementar la interfaz, obtuve errores de compatibilidad.
La siguiente es una demostración simple del problema con el que me he encontrado:
interface iFoo
{
public function bar (string $baz) : self;
}
class Foo implements iFoo
{
public function bar (string $baz) : self
{
echo $baz . PHP_EOL;
return $this;
}
}
(new Foo ()) -> bar ("Fred")
-> bar ("Wilma")
-> bar ("Barney")
-> bar ("Betty");
El resultado esperado fue:
Fred Wilma Barney Betty
Lo que realmente obtengo es:
Error fatal de PHP: Declaración de Foo :: bar (int $ baz): Foo debe ser compatible con iFoo :: bar (int $ baz): iFoo en test.php en la línea 7
La cosa es que Foo es una implementación de iFoo, por lo que puedo decir, la implementación debería ser perfectamente compatible con la interfaz dada. Presumiblemente podría solucionar este problema cambiando la interfaz o la clase de implementación (o ambas) para devolver la pista a la interfaz por nombre en lugar de usar self
, pero tengo entendido que semánticamente self
significa "devolver la instancia de la clase en la que acaba de llamar al método ". Por lo tanto, cambiarlo a la interfaz significaría en teoría que podría devolver cualquier instancia de algo que implemente la interfaz cuando mi intención es que la instancia invocada sea lo que se devolverá.
¿Es esto un descuido en PHP o es una decisión de diseño deliberada? Si es lo primero, ¿hay alguna posibilidad de que se solucione en PHP 7.1? Si no es así, ¿cuál es la forma correcta de devolver la sugerencia de que su interfaz espera que devuelva la instancia en la que acaba de llamar al método para encadenar?
fuente
self
se supone que funciona el tipo de devolución?self
que signifique "Devuelve la instancia a la que llamaste , y no otra instancia que implemente la misma interfaz". Creo recordar que Java tenía un tipo de retorno similar (aunque ha pasado un tiempo desde que hice cualquier programación en Java)Respuestas:
self
no se refiere a la instancia, se refiere a la clase actual. No hay forma de que una interfaz especifique que se debe devolver la misma instancia ; si lo usaself
de la manera que está intentando, solo se impondrá que la instancia devuelta sea de la misma clase.Dicho esto, las declaraciones de tipo de retorno en PHP deben ser invariantes, mientras que lo que está intentando es covariante.
Su uso de
self
es equivalente a:interface iFoo { public function bar (string $baz) : iFoo; } class Foo implements iFoo { public function bar (string $baz) : Foo {...} }
que no está permitido.
El RFC de declaraciones de tipo de devolución tiene esto que decir :
Por el momento, al menos lo mejor que puede hacer es:
interface iFoo { public function bar (string $baz) : iFoo; } class Foo implements iFoo { public function bar (string $baz) : iFoo {...} }
fuente
static
funcionara, pero ni siquiera se reconocestatic
se está agregando a PHP 8.También puede ser una solución, que no defina explícitamente el tipo de retorno en la Interfaz, solo en PHPDoc y luego puede definir el tipo de retorno determinado en las implementaciones:
interface iFoo { public function bar (string $baz); } class Foo implements iFoo { public function bar (string $baz) : Foo {...} }
fuente
Foo
simplemente usarself
.En caso de que, cuando desee forzar desde la interfaz, ese método devolverá el objeto, pero el tipo de objeto no será el tipo de interfaz, sino la clase en sí, entonces puede escribirlo de esta manera:
interface iFoo { public function bar (string $baz) : object; } class Foo implements iFoo { public function bar (string $baz) : self {...} }
Funciona desde PHP 7.4.
fuente
PHP 8 agregará "tipo de retorno estático" que resolverá su problema.
Consulte este RFC: https://wiki.php.net/rfc/static_return_type
fuente
Esto me parece el comportamiento esperado.
Simplemente cambie su
Foo::bar
método para regresar eniFoo
lugar deself
y terminar con él.Explicación:
self
como se usa en la interfaz significa "un objeto de tipoiFoo
".self
como se usa en la implementación significa "un objeto de tipoFoo
".Por lo tanto, los tipos de devolución en la interfaz y la implementación claramente no son los mismos.
Uno de los comentarios menciona Java y si tendría este problema. La respuesta es sí, tendría el mismo problema si Java le permitiera escribir código así, lo cual no es así. Dado que Java requiere que use el nombre del tipo en lugar del
self
acceso directo de PHP , nunca verá esto. (Consulte aquí una discusión sobre un problema similar en Java).fuente
self
similar a declararMyClass::class
?