sábado, 11 de fevereiro de 2012

Usando traços em PHP 5,4

Minimizando a duplicação de código através de uma melhor organização e reutilização de código é uma meta importante de Programação Orientada a Objetos. Mas em PHP que por vezes pode ser difícil por causa das limitações do modelo de herança simples que ele usa, você pode ter alguns métodos que você gostaria de usar em várias classes, mas eles podem não se encaixar bem na hierarquia de herança.

Linguagens como C + + e Python permitem-nos para herdar de várias classes que resolve este problema até certo ponto, e mixins em Ruby nos permite misturar a funcionalidade de uma ou mais classes sem o uso de herança. Mas a herança múltipla tem problemas como o Problema Diamante problema, e mixins pode ser um mecanismo complexo para se trabalhar.

Neste artigo vou discutir características, um novo recurso introduzido no PHP 5.4 para superar essas questões. O conceito de traços em si não é novidade para a programação e é usado em outras linguagens como Perl e Scala. Eles nos permite reutilizar código horizontalmente entre as classes independentes em hierarquias de classes diferentes.

O que um traço Looks Like
Um traço é semelhante a uma classe abstrata que não pode ser instanciado por conta própria (embora mais frequentemente é comparado a uma interface). A documentação do PHP define as características como segue:
Traços é um mecanismo para a reutilização de código em linguagens de herança simples, como PHP. Um traço se destina a reduzir algumas limitações de herança simples, permitindo que um desenvolvedor de reutilizar conjuntos de métodos livremente em várias classes independentes que vivem em hierarquias de classes diferentes.

Vamos considerar este exemplo:

<? Php
classe DbReader estende Mysqli
{
}

classe FileReader estende SplFileObject
{
}

Seria um problema se ambas as classes necessárias algumas funcionalidades comuns, por exemplo, tornando ambos singletons. Desde o PHP não suporta herança múltipla, uma ou outra classe cada um terá para implementar o código necessário para suportar o padrão Singleton ou haverá uma hierarquia de herança que não faz sentido. Traços de oferecer uma solução para exatamente esse tipo de problema.

<? Php
traço Singleton
{
    privada estática $ instance ;
    público estático função getInstance () {
        se (! (self :: $ instance auto instanceof)) {
            self :: $ instance = nova auto;
        }
        retornar self :: $ instance ;
    }
}

classe DbReader estende ArrayObject
15
{
    usar Singleton;
}

classe   FileReader
{
    usar Singleton;
}

O traço Singleton tem uma aplicação direta do padrão Singleton com um método estático getInstance () que cria um objeto da classe usando esta característica (se já não estiver criado) e devolve-lo.

Vamos tentar criar os objetos dessas classes usando o método getInstance () .

<? Php
$ A = DbReader :: getInstance ();
$ B = FileReader :: getInstance ();
var_dump ( $ a );  / object / (DbReader)
var_dump ( $ b );  / object / (FileReader)

Podemos ver que $ a é um objeto de DbReader e $ b é um objeto de FileReader , mas ambos estão se comportando como singletons. O método de Singleton foi injetado horizontalmente para as classes que o utilizam.
Traços não impõem qualquer semântica adicionais sobre a classe. De certa forma, você pode pensar nisso como uma cópia do compilador assistida e um mecanismo de colar onde os métodos do traço é copiado para a classe de composição.
Se estivéssemos simplesmente subclassificação DbReader de um pai com uma privada exemplo $ propriedade, a propriedade não seria mostrado no despejo de ReflectionClass :: export () . E ainda com traços, não é!

Classe [classe FileReader] {
  @ @ Home/shameer/workplace/php54/index.php / 19-22

  - Constantes [0] {
  }
  - Propriedades estáticas [1] {
    Propriedade [private static $ _instance]
  }
  - Os métodos estáticos [1] {
    Método [instância método public static] {
      @ @ / Home/shameer/workplace/php54/index.php 6-11
    }
  }
  - Propriedades [0] {
  }
  - Métodos de [0] {
  }
}

Características múltiplas
Até agora temos usado apenas um traço com uma classe, mas em alguns casos talvez seja necessário incorporar a funcionalidade de mais de uma característica.

<? Php
traço Olá
{
    função sayHello () {
        echo "Olá" ;
    }
}

traço Mundial
{
    função sayWorld () {
        echo "O Mundo" ;
    }
}

classe MyWorld
{
    usar Olá, Mundo;
}

$ Mundial = novo MyWorld ();
echo $ mundial . -> sayHello () "" . mundo $ -> sayWorld (); Mundo / / Olá

Aqui temos duas características, Hello e do Mundo . Traço Olá só é capaz de dizer "Olá" e traço Mundial pode dizer "mundo". No MyWorld classe temos aplicado Olá e do Mundo para que o MyWorld objeto terá métodos de ambas as características e ser capaz de dizer "Olá Mundo".

Traços Composto de Traços
Conforme a aplicação cresce, é bem possível que teremos um conjunto de traços que são usados ​​em diferentes classes. PHP 5,4 nos permite ter traços de compostos de outras características, para que possamos incluir apenas uma vez de um número de características em todas essas classes. Isso nos permite reescrever o exemplo anterior da seguinte forma:

<? Php
traço HelloWorld
{
    usar Olá, Mundo;
}
classe MyWorld
{
    usar HelloWorld;
}

$ Mundial = novo MyWorld ();
echo $ mundial . -> sayHello () "" . mundo $ -> sayWorld (); Mundo / / Olá

Aqui nós criamos o traço HelloWorld , usando traços Olá e do Mundo, e incluiu no MyWorld . Desde o HelloWorld traço tem métodos dos outros dois traços, é exatamente o mesmo como se tivéssemos incluindo os dois traços na classe nós mesmos.

Ordem de Precedência
Como já mencionado, traços trabalhar como se os seus métodos têm sido copiado e colado nas classes usando eles e eles são totalmente aplainado para a definição das classes '. Pode haver métodos com o mesmo nome em diferentes características ou na própria classe. Você pode se perguntar qual deles estará disponível no objeto da classe filha.

A ordem de precedência é:
os métodos de uma substituição de característica hereditária métodos da classe pai
os métodos definidos nos métodos atuais de sobreposição de classe a partir de um traço
Isso fica claro no exemplo a seguir:

<? Php
traço Olá
{
    função sayHello () {
        retornar "Olá" ;
    }
    função sayWorld () {
        retornar "World Traço" ;
    }

    função sayHelloWorld () {
        echo $ this -> sayHello (). "" . $ this -> sayWorld ();
    }

    função sayBaseWorld () {
        echo $ this -> sayHello (). "" . parent :: sayWorld ();
    }
}

classe Base de Dados
{
    função sayWorld () {
        retornar "Base Mundial" ;
    }
}

classe HelloWorld estende Base de Dados
{
    utilizar Olá;
    função sayWorld () {
        retornar "World" ;
    }
}

$ H =  novo HelloWorld ();
$ H -> sayHelloWorld (); Mundo / / Olá
$ H -> sayBaseWorld (); Mundial Base / / Olá

Temos um HelloWorld classe derivada da base de dados , e ambas as classes tem um método chamado sayWorld () , mas com diferentes implementações. Além disso, nós incluímos o traço Olá no HelloWorld classe.
Nós temos dois métodos, sayHelloWorld () e sayBaseWorld () , o primeiro dos quais chama sayWorld () que existe em ambas as classes, bem como no traço. Mas na saída, podemos ver a partir da classe infantil foi chamado. Se precisarmos de fazer referência ao método da classe pai, podemos fazê-lo usando a palavra-chave pai, como mostrado na sayBaseWorld () método.
Resolução de Conflitos e Aliasing

Quando se utiliza características múltiplas, pode haver uma situação em que diferentes características usar os nomes mesmo método. Por exemplo, o PHP irá dar um erro fatal se você tentar executar o código a seguir porque de nomes de métodos conflitantes:

<? Php
traço Jogo
{
    função play () {
        echo "Jogar um jogo" ;
    }
}

traço Música
{
    função play () {
        echo "Reprodução de música" ;
    }
}

classe Jogador
{
    usar Game Music,;
}

$ Leitor = novo Player ();
$ Jogador -> play ();

Tais conflitos de características não são resolvidos automaticamente para você. Em vez disso, você deve escolher qual método deve ser usado dentro da classe de compor usando a palavra-chave insteadof .

<? Php
classe Jogador
{
    usar Game Music, {
        Música :: jogo insteadof Jogo;
    }
}

$ Leitor = novo Player ();
$ Jogador -> play (); / / Reprodução de música

Aqui optamos por usar o play () método da Música traço dentro da classe compondo assim a classe Jogador vai tocar música, não um jogo.

No exemplo acima, um método foi escolhido em relação ao outro a partir de duas características. Em alguns casos você pode querer manter os dois, mas ainda evitar conflitos. É possível introduzir um novo nome para um método em um traço como um alias. Um alias não muda o nome do método, mas oferece um nome alternativo pelo qual pode ser invocado. Alias ​​são criados usando a palavra-chave como .

<? Php
classe Jogador
{
    usar Game Music, {
        Jogo :: como jogabilidade;
        Música :: jogo insteadof Jogo;
    }
}

$ Leitor = novo Player ();
$ Jogador -> play (); / / Reprodução de música
$ Jogador -> jogabilidade (); / / Jogar um jogo

Agora, qualquer objecto da classe do jogador terá um método de jogo () , que é o mesmo que o jogo de Jogo :: () . Aqui deve notar-se que tenham resolvido todos os conflitos explicitamente, mesmo depois de serrilhado.

Reflexão
A API de reflexão é uma das características fortes do PHP para analisar a estrutura interna de interfaces, classes e métodos e engenharia reversa-los. E já que estamos falando de características, você pode estar interessado em saber sobre o suporte a API de reflexão para os traços. No PHP 5.4, quatro métodos foram adicionados ao ReflectionClass para obter informações sobre as características de uma classe.
Podemos usar ReflectionClass :: getTraits () para obter uma matriz de todos os traços utilizados em uma classe. O ReflectionClass :: getTraitNames () método irá simplesmente retornar um array de nomes de traço dessa classe. ReflectionClass :: isTrait () é útil para verificar se algo é um traço ou não.
Na seção anterior discutimos ter aliases para as características para evitar colisões devido a traços com o mesmo nome. ReflectionClass :: getTraitAliases () irá retornar uma matriz de traço alcunhas mapeada pelo seu nome original.

Outros Recursos
Para além do acima mencionado, existem outras características que faz com que as características mais interessante. Sabemos que na herança clássica as propriedades particulares de uma classe não pode ser acessado por classes filhas. Traços pode acessar as propriedades privadas ou métodos das classes que compõem, e vice-versa! Aqui está um exemplo:

<? Php
traço Mensagem
{
    função alert () {
        echo $ this -> Mensagem;
    }
}

classe Mensageiro
{
    utilizar Mensagem;
    privada $ mensagem = "Esta é uma mensagem" ;
}

$ Messenger = novo Messenger;
$ Mensageiro -> alert (); / / Esta é uma mensagem

Como as características são completamente achatada para a classe composta por eles, qualquer propriedade ou método do traço vai se tornar uma parte dessa classe e temos acesso a eles, tal como todas as propriedades de outras classes ou métodos.
Podemos até ter métodos abstratos em um traço para reforçar a classe compor para implementar esses métodos. Por exemplo:

<? Php
traço Mensagem
{
    privada mensagem $ ;

    função alert () {
        $ This -> define ();
        echo $ this -> Mensagem;
    }
    abstrata função define ();
}

classe Mensageiro
{
    utilizar Mensagem;
    funcionar define () {
        $ Essa -> Mensagem = "Mensagem personalizada" ;
    }
}

$ Messenger = novo Messenger;
$ Mensageiro -> alert (); Mensagem / / Custom

Aqui nós temos uma característica mensagem com um método abstrato define () . Ela exige que todas as classes que usam essa característica para implementar o método. Caso contrário, o PHP irá dar um erro dizendo que não há um método abstrato que não foi implementado.
Ao contrário de traços em Scala, traços em PHP pode ter um construtor mas ele deve ser declarado público (um erro será lançada se é privada ou protegida). De qualquer forma, ser cautelosos ao usar construtores em traços, no entanto, porque pode levar a colisões indesejadas nas classes que compõem.

Nenhum comentário :

Postar um comentário

Total de visualizações de página