Como os novos tipos de interseção no PHP 8.1 oferecem mais flexibilidade
Os tipos de interseção são um novo recurso do sistema de tipos que vem no PHP 8.1. Eles permitem que você digite valores de dicas que devem satisfazer mais de uma restrição de tipo. O PHP &’ já tem tipos de união que combinam tipos com um “ ou ” lógico; cláusula; os tipos de interseção oferecem um “ e ” cláusula em vez disso.
Alguns desenvolvedores já digitam interseções de dicas usando anotações PHPDoc. A adição de suporte nativo é um passo à frente, pois os tipos serão realmente aplicados no tempo de execução. Eles também são totalmente compatíveis com a herança de classe, ajudando a reduzir o risco de erros devido a anotações desatualizadas ou incompatíveis.
Sintaxe básica
A sintaxe do tipo de interseção é semelhante aos tipos de união:
classe DemoClass & # 123; public Countable | Stringable $ Union; public Countable & Stringable $ Intersection; & # 125;
Neste exemplo, $ Union será satisfeito por qualquer valor que sejaCountable ou Stringable. $ Intersection só aceitará valores que atendam a ambas as restrições. Você obterá um TypeError se atribuir à propriedade um valor que implementa um ou nenhum dos tipos sugeridos.
Os tipos de intersecção são suportados em todos os lugares em que as dicas de tipo funcionam. Você pode usá-los com definições de propriedade, parâmetros de função e valores de retorno.
Ao contrário dos tipos de união, as interseções podem digitar apenas interfaces e classes de dicas. Uma interseção escalar como int e string não tem sentido, pois nunca poderia ser satisfeita. O tipo misto também é proibido, porque cada valor satisfará sua restrição.
Variância de tipo
Os tipos de interseção respeitam as regras de variância existentes do PHP. Os tipos de retorno de métodos substituídos devem ser covariantes, enquanto os tipos de parâmetros são contravariantes. As propriedades da classe são sempre invariáveis, portanto, os filhos não podem alterar a definição do tipo, a menos que a nova assinatura seja um subtipo e supertipo da herdada.
Publicidade
Para valores de retorno, as regras de variação significam que você pode adicionar outros tipos de interseção em métodos substituídos. Os métodos também podem remover, mas não adicionar, tipos de interseções usados como parâmetros. Essas regras reforçam o princípio de substituição de Liskov.
interface I1 & # 123; publicfunction method1 & # 40; A & B $ demo & # 41 ;: X & Y; publicfunction method2 & # 40; A & B $ demo & # 41 ;: X & Y; & # 125; a interface I2 estende I1 & # 123; // Método de função pública PERMITIDO1 & # 40; A $ demo & # 41 ;: X & Y & Z; // NÃO PERMITIDO método de função pública2 & # 40; A & B & C $ demo & # 41 ;: X; & # 125;
No caso do método1, as restrições não foram realmente alteradas. Você está afirmando que o método substituído pode realmente funcionar com qualquer A, mesmo se não for também um X. É menos específico, o que resulta em variação de parâmetro aceitável. A declaração de retorno é mais específica, afirmando que o valor implementará X, Y e Z; neste cenário, adicionar especificidade não quebra o contrato, pois o valor ainda será aceito por qualquer coisa que digite I1.
A substituição do método2 foi quebrada em ambas as contagens. Ao exigir que o parâmetro de entrada satisfaça A, B e C, ele não é mais um substituto imediato para I1. Da mesma forma, o método 2 apenas garante que o valor de retorno será uma instância de X. Isso quebra o contrato, pois qualquer coisa que indique o tipo I1 exige que o valor satisfaça a interseção de X e Y.
As interseções invertem as regras práticas de variância dos tipos de união. À medida que as uniões são combinadas usando “ ou, ” filhos podem adicionar tipos de parâmetro e remover tipos de retorno. O princípio de substituição de Liskov é satisfeito quando o efeito de alargamento e estreitamento das restrições de tipo é revertido.
Tal como acontece com os tipos de união, as regras de variância também se aplicam aos tipos que constituem uma interseção – essas são as partes X e Y individuais de X e Y. Você pode restringir um tipo ao devolvê-lo – informando que você &’ retornará uma subclasse – ou ampliá-lo como parâmetro, aceitando uma superclasse.
Publicidade
As interseções também possuem algumas regras especiais sobre aliasing e implementações concretas. Se você digitar a sugestão X e Y, mas escrever uma interface que Z estenda X, Y, é lógico que Z satisfaça a restrição. Consequentemente, você pode digitar Z em vez de X e Y sempre que a covariância for permitida:
Teste de interface
estende X, Y & # 123; & # 125; interface Demo1 & # 123; demonstração de função pública & # 40; & # 41 ;: X & Y; & # 125; interface Demo2 & # 123; demonstração de função pública & # 40; & # 41 ;: Teste; & # 125;
Isso permite que você digite uma sugestão de classe ou interface concreta se depender de funcionalidades adicionais. É aceitável, desde que todas as restrições na interseção sejam satisfeitas pela dica de tipo final.
Quando usar tipos de interseção?
Os tipos de interseção são para os momentos em que você deseja ter certeza de que um valor satisfaz uma interface composta sem realmente definir essa interface. As versões anteriores do PHP não forneciam nenhum suporte nativo para isso, então você precisava adicionar uma confusão de clichês extras à sua base de código:
interface CountableStringable estende Countable, Stringable & # 123; // ... & # 125; classe FakeArray implementa CountableStringable & # 123; publicarray $ items = & # 91; & # 93 ;; publicfunctioncount & # 40; & # 41 ;: int & # 123; returncount & # 40; $ this- > items & # 41 ;; & # 125; publicfunction __toString & # 40; & # 41 ;: string & # 123; returnimplode & # 40; & quot ;, & quot ;, $ this- > items & # 41 ;; & # 125; & # 125; classe DemoClass & # 123; public CountableStringable $ Value; & # 125;
Isso leva a um excesso de interfaces rasas semelhantes a stub para obter um comportamento básico de interseção. Embora os desenvolvedores de PHP tenham sobrevivido sem interseções até o momento, sua presença ajuda a solidificar as capacidades compostas do sistema de tipos. O uso de interseções nativas cria um código mais limpo e intuitivo.
E quanto aos tipos compostos?
Não é possível combinar tipos de interseção e união na mesma dica de tipo. Embora seja tecnicamente possível, ele foi omitido da RFC atual, pois há ambigüidades em torno da sintaxe, precedência e variação.
Os tipos compostos continuam sendo uma ideia para o futuro. Se eles fossem adicionados, você poderia começar a adicionar dicas de tipo complexas como esta:
classe DemoClass & # 123; public Countable & Stringable | CountableStringable $ Intersection; & # 125;
Publicidade
Esta classe de exemplo combina as duas implementações acima. Se funcionasse, permitiria que você adotasse tipos de interseção nativos enquanto mantinha a compatibilidade com as classes antigas usando o método “ falso ” abordagem.
Tipos compostos completos completariam o manuseio de múltiplos tipos facilitado por uniões e cruzamentos. Enquanto isso, você precisará continuar escrevendo suas próprias interfaces compostas nesses cenários.
Resumo
Os tipos de interseção estão chegando ao PHP 8.1 e irão desbloquear possibilidades mais avançadas dentro do sistema de tipos. Estender as opções em torno dos tipos compostos reduz a quantidade de código que você precisa escrever quando há suporte para várias interfaces.
As interseções são um recurso opcional que não introduzirá nenhuma incompatibilidade com o código existente. O RFC foi implementado na terceira versão alfa do PHP 8.1. O lançamento final chegará no final de novembro no final deste ano.
Nenhum comentário