Uma introdução prática à Reflection no PHP
São inúmeras linguagens de programação que disponibiliza mecanismos para se fazer reflexão em estruturas de dados, no PHP isso também não seria diferente. Mas antes precisamos entender, o que é reflexão?
Em ciência da computação, reflexão computacional (ou somente reflexão) é a capacidade de um programa observar ou até mesmo modificar sua estrutura ou comportamento. — Wikipedia.
Se você tem uma pequena vivência com o PHP, provavelmente já deve ter encontrado algum código “mágico” que resolve algum problema. Um exemplo um pouco comum é a injeção de dependência do Laravel (que não é exclusividade da ferramenta), vamos ver um exemplo (caso você não tenha vivência com o Laravel, não tem problema):
|
|
Se analisarmos o exemplo, vemos que o construtor da nossa classe
UserController
espera uma instância de UserRepository
, certo? Até aqui, sem
problemas, apenas PHP. A “mágica” do Laravel acontece quando o próprio framework
cria a instância de UserRepository
e passa automaticamente para o nosso
controller. Para isso, o framework utiliza um padrão chamado service container
que por outro lado utiliza uma técnica chamada injeção de dependência.
Basicamente, o service container analisa que a classe UserController
precisa
de um UserRepository
para ser instanciado e cria essa instância, mas como ele
sabe que ele precisa dessa instância? Com reflexão.
Trabalhar com reflexão no PHP é possível graças as classes mágicas de Reflection do PHP. Essas classes estão disponíveis no core da linguagem desde a versão 5, então não é necessário fazer nenhuma instalação. Existem algumas classes de Reflection no PHP, sendo que cada uma depende de onde você vai aplicar:
- ReflectionClass — Utilizar em classes;
- ReflectionExtension — Utilizar em extensões;
- ReflectionFunction — Utilizar em funções;
- ReflectionFunctionAbstract — Utilizar em funções abstratas;
- ReflectionMethod — Utilizar em métodos;
- ReflectionObject — Utilizar em objetos;
- ReflectionParameter — Utilizar em parâmetros (de métodos ou funções);
- ReflectionProperty — Utilizar em propriedades de classes;
- ReflectionType — Utilizar para saber sobre tipos de retorno;
- ReflectionGenerator — Utilizar em geradores.
Vamos seguir com a ideia do exemplo em Laravel, mas agora fora do framework.
Imagine que precisamos instanciar a classe UserController
que espera uma
instância de UserRepository
, tudo isso fora do framework.
|
|
Analisando o nosso pequeno exemplo podemos ver que precisamos descobrir o que o
construtor necessita para que possamos instanciar, tudo isso de forma “mágica”,
utilizando reflexão. Se olharmos a lista das classes disponíveis, podemos
notar que existem 2 tipos de classes que chamam a nossa atenção para esse caso,
são as *ReflectionParameter *e ReflectionMethod, porem olhando a assinatura é
possível notar que ReflectionParameter não serve diretamente para o nosso
caso, pois o primeiro argumento é um
callable e não é
o caso do nosso __construct
, então sobra o ReflectionMethod. Então, basta
instanciar a classe ReflectionMethod passando o nosso controller junto com o
nome do nosso método que é __construct
.
|
|
Criamos a nossa reflexão do método __construct
utilizando a classe
ReflectionMethod. O interessante de se analisar é que o método
getParameters()
da classe de reflexão retorna uma lista de
ReflectionParameter que representa cada parâmetro, ou seja, mesmo que não
utilizando o ReflectionParameter diretamente acabamos chegando na ideia do
mesmo resultado, tudo isso graças à uma ótima API das classes. Isso não é
particularidade apenas da ReflectionMethod, podemos fazer o mesmo utilizando a
classe ReflectionClass, criando uma reflexão para o nosso controller e
analisando o construtor do alvo.
|
|
Dessa maneira, conseguimos começar do nível de cima e ir acessando às nossas necessidades até o último nível. Com esses pequenos exemplos, conseguimos começar a entender como utilizar a API de reflexão do PHP e o básico (bem básico) de como um service container funciona.
Os exemplos podem ter ficado um pouco longos mas são bem simples, pois são apenas um começo de como a reflexão do PHP funciona, de qualquer maneira aconselho você a começar a testar cada uma das classes e entender suas particularidades e funcionalidades.
Espero que isso te ajude de alguma forma.