ATUALIZAÇÃO : o PHP 7.4 agora oferece suporte a covariância e contravariância que aborda a principal questão levantada nesta questão.
Eu tive um problema com o uso de dicas de tipo de retorno no PHP 7. Meu entendimento é que a sugestão : self
significa que você pretende que uma classe de implementação retorne a si mesma. Portanto, usei : self
em minhas interfaces para indicar isso, mas quando tentei realmente implementar a interface, obtive erros de compatibilidade.
A seguir está uma demonstração simples do problema que encontrei:
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");
A saída esperada era:
Fred Wilma Barney Betty
O que eu realmente consigo é:
Erro fatal do PHP: Declaração de Foo :: bar (int $ baz): Foo deve ser compatível com iFoo :: bar (int $ baz): iFoo em test.php na linha 7
O fato é que Foo é uma implementação do iFoo, então pelo que eu posso dizer, a implementação deve ser perfeitamente compatível com a interface fornecida. Eu poderia provavelmente corrigir esse problema alterando a interface ou a classe de implementação (ou ambas) para retornar a dica da interface pelo nome em vez de usar self
, mas meu entendimento é que semanticamente self
significa "retornar a instância da classe na qual você acabou de chamar o método " Portanto, alterá-lo para a interface significaria, em teoria, que eu poderia retornar qualquer instância de algo que implementa a interface quando minha intenção é que a instância invocada seja o que será retornado.
Isso é um descuido no PHP ou é uma decisão de design deliberada? Se for o primeiro, há alguma chance de vê-lo corrigido no PHP 7.1? Se não, qual é a maneira correta de retornar a dica de que sua interface espera que você retorne a instância na qual acabou de chamar o método para encadeamento?
fonte
self
tipo de retorno deve funcionar?self
significar "Retorne a instância em que você chamou isso, e não alguma outra instância que implemente a mesma interface". Parece que me lembro de Java tinha um tipo de retorno semelhante (embora já faça um tempo desde que fiz qualquer programação Java)Respostas:
self
não se refere à instância, mas à classe atual. Não há como uma interface especificar que a mesma instância deve ser retornada - usarself
da maneira que você está tentando apenas forçaria que a instância retornada fosse da mesma classe.Dito isso, as declarações de tipo de retorno em PHP devem ser invariáveis, enquanto o que você está tentando é covariante.
Seu uso de
self
é equivalente a:interface iFoo { public function bar (string $baz) : iFoo; } class Foo implements iFoo { public function bar (string $baz) : Foo {...} }
o que não é permitido.
O RFC de declarações de tipo de retorno tem o seguinte :
Por enquanto, pelo menos o melhor que você pode fazer é:
interface iFoo { public function bar (string $baz) : iFoo; } class Foo implements iFoo { public function bar (string $baz) : iFoo {...} }
fonte
static
funcionasse, mas nem mesmo é reconhecidastatic
está sendo adicionado ao PHP 8.Também pode ser uma solução, que você não defina explicitamente o tipo de retorno na Interface, apenas no PHPDoc e então você pode definir o tipo de retorno certo nas implementações:
interface iFoo { public function bar (string $baz); } class Foo implements iFoo { public function bar (string $baz) : Foo {...} }
fonte
Foo
apenas usarself
.No caso, quando você quiser forçar da interface, esse método retornará objeto, mas o tipo de objeto não será o tipo de interface, mas a própria classe, então você pode escrever desta forma:
interface iFoo { public function bar (string $baz) : object; } class Foo implements iFoo { public function bar (string $baz) : self {...} }
Está funcionando desde o PHP 7.4.
fonte
O PHP 8 adicionará "tipo de retorno estático" que resolverá seu problema.
Confira este RFC: https://wiki.php.net/rfc/static_return_type
fonte
Este parece o comportamento esperado para mim.
Apenas altere seu
Foo::bar
método para retornar emiFoo
vez deself
e pronto.Explicação:
self
conforme usado na interface significa "um objeto do tipoiFoo
".self
conforme usado na implementação significa "um objeto do tipoFoo
".Portanto, os tipos de retorno na interface e na implementação claramente não são os mesmos.
Um dos comentários menciona Java e se você teria esse problema. A resposta é sim, você teria o mesmo problema se Java permitisse que você escrevesse código assim - o que não é verdade. Como o Java requer que você use o nome do tipo em vez do
self
atalho do PHP , você nunca verá isso de fato. (Veja aqui uma discussão sobre um problema semelhante em Java.)fonte
self
, declarar é semelhante a declararMyClass::class
?