Oi Vinicius, beleza?
Não terá replicação de código pois as interfaces é justamente para padronizar comportamentos iguais entre classes, porém, esses comportamentos são implementados de formas diferentes.
Por exemplo:
Imagine que você possui um site/sistema e você quer enviar um email de boas vindas logo após o cadastro de um usuário novo. Existem várias formas e bibliotecas para você enviar um email e isso deixaria seu código bastante acoplado, o que fazemos então? Padronizamos o comportamento de enviar um email através de uma interface, um exemplo:
interface EnviadorDeEmail
{
public function envia(string $titulo, string mensagem);
}
class EnviadorDeEmailComMail implements EnviadorDeEmail
{
public function envia(string $titulo, string $mensagem)
{
//implementação com a funcão mail do PHP
}
}
class EnviadorDeEmailComPHPMailer implements EnviadorDeEmail
{
public function envia(string $titulo, string $mensagem)
{
//implementação com lib do PHPMailer
}
}
Class CadastroDeUsuario
{
private DaoUsuario $dao;
private EnviadorDeEmail $enviador;
public function __construct(DaoUsuario $dao, EnviadorDeEmail $enviador)
{
$this->dao = $dao;
$this->enviador = $enviador;
}
//codigo da classe..
}
Observe que a classe CadastroDeUsuario
posso instancia-la tanto com um EnviadorDeEmailComMail
ou com EnviadorDeEmailComPHPMailer
, pois ambas são uma implementação de EnviadorDeEmail
. Observe a flexibilidade que as interfaces oferecem ao código, deixando mais desacoplado, manutenível, etc...
Caso queira realmente simular herança múltipla utilize as traits, mas tenha cuidado com essa história de herança múltipla.
Bons estudos.