Ponteiros e Referências no PHP

Olá Galera!

Hoje falarei de um assunto não muito popular entre os programadores web iniciantes. Irei abordar a sintaxe e a utilização de ponteiros e referências no PHP. Decidi fazer esse post depois da questão 34 do Póscomp 2011 que deu uma certa nostalgia das linguagens C e C++ e como o PHP é filho delas, eis o post =)

Resolvi separar este post por partes, são 5, assim fica mais fácil e você irá direto ao ponto que lhe interessa mais:

 

Parte I: Ponteiros

Você pode-se perguntar: “Mas existem ponteiros no PHP?” ou “Como funcionam os ponteiros no PHP?” E ai está um ponto muito interessante para se tratar, por definição entende-se que ponteiros são um tipo de dado que define um variável que aponta (entendeu o trocadilho?) para um determinado endereço de memória. No entanto sabemos que o PHP possui tipagem dinâmica e que a alocação de memória também é dinâmica (você não precisa declarar previamente a variável), ou seja, dessa maneira eu percebo que a implementação de ponteiros é implícita. Caso você já tenha trabalho com ponteiros mais adiante você irá perceber nas referências e passagens por referência a funcionamento implícito dos ponteiros, ou se você nunca ouviu falar de tal, aqui você não verá! hehe

Parte II: Referências

Esse é um ponto muito interessante do PHP, a princípio você pode achar inútil, veja primeiramente a sintaxe básica, e posteriormente irei demosntrar como funciona:

<?php

$a = 'Exemplo';
$b = &$a;

var_dump($a); // saída = Exemplo
var_dump($b); // saída = Exemplo

?>

Veja que o resultado de de $b é idêntico ao de $a, isto porque $b referência exatamente o mesmo valor que $a possa conter, isto é, $b irá sempre conter o valor de $a, porque $b faz referência ao mesmo endereço de memória onde $a guarda seus valores. Por isso pode-se afirmar que $a e $b tem o mesmo endereço de memória.

Agora, note que se modificarmos o valor de $b o valor de $a também será:

<?php

$b = 'Modifique o valor';

var_dump($a); // saída = Modifique o valor
var_dump($b); // saída = Modifique o valor

?>

Importante: sabemos que $b é uma referência a variável $a, se tentarmos destrutir a variável $b teremos que utilizar a função unset(), pois se na tentativa de destruir atribuirmos NULL a $b, este valor também será atribuido a $a.

Veja a destruição da variável de referência $b:

<?php

unset($b);

var_dump($b); // Resultará em um erro NOTICE de variável indefinida 

?>

Tudo bem Tiago, eu entedi, mas onde poderei usar esta funcionalidade? Muito simples, imagine que você tem uma variável de sessão, muito comprida, abaixo você tem um exemplo (muito simples) de código onde você pode usar a atribuição por referência:

<?php

$_SESSION['sou_um_nome_de_variavel_grande'] = 'sou pequeno';
$sessao = &$_SESSION['sou_um_nome_de_variavel_grande'];

var_dump($sessao); // saída = sou pequeno 

?>

Parte III: Passagem por Referência em Funções

Na declaração de uma função você pode definir os parametos de entrada, sendo que eles podem ser referências e assim a função poderá motificar o valor dessas variáveis (que você passou nos parâmetros) sem ter que retornar o valor processado. No entanto nota-se que este artifico não tem efeito se usado para economizar o uso de memória da sua aplicação, dada a maneira que o PHP trata as referências. Eu pessoalmente não achei muito semântico usar este tipo de sintaxe, pois torna o debug do código um pouco mais dificil, veja como funciona no exemplo abaixo:

<?php

$salario = 2000.00;

somar($salario);

var_dump($salario); // saída = 3000.00

function somar(&$valor)
{
	$valor = $valor+1000;
}

?>

Perceba que não há o operador de referência (&) na chamada da função somar() e nem na passagem dos valores. Na declaração da função você especificou que a entrada dos parâmetros seria por referência (eis porque disse do problema do debug).

Observe que o valor da variável $salario foi alterado, sem ser exatamente retornado pela função, isso acontece porque a função modificou o conteúdo da variável $salario diretamente no local da memória onde ela estava, diferentemente da passagem convencional onde uma segunda variável é criada e o valor é copiado, para ficar mais claro veja  diferença abaixo, onde o parametro não é passado por referencia:

<?php

$salario = 2000.00;

$salario = somar($salario);

var_dump($salario); // saída = 3000.00

function somar($valor)
{
	return $valor+1000;

}

?>

Faz a mesma coisa sem passar por referência e é mais fácil de debugar, certo? =)

Parte IV: Retornando Referências

Citando novamente o artifício das referências para aumentar a performance, o manual do PHP de cara já diz isso:

Retorno por referência é útil quando você precisa utilizar uma função para localizar variável cuja referência precisa ser obtida. Não use retorno por referência para aumentar performance, a engine é esperta o bastante para otimizar isto para você. Somente retorne referências quando você tem uma razão técnica para isso!

Assim, o retorno por referência é utilizado apenas por razões técnicas, dada a arquitetura da sua aplicação. Vou tomar como exemplo a mesma funcionalidade que você pode encontrar no manual do PHP, assim imagine a situação onde você precise alterar o valor de uma propriedade de um determinado objeto, e para isso você não tem acesso direto a essa propriedade, mas se o método de retorno for por referência você poderá alterar o valor dessa propriedade, sem chamar o método setter dela. Para ficar mais fácil, veja o exemplo abaixo:

<?php

class Funcionario
{
	public static $salario = 2000.00;

	public function &getSalario()
	{
		return self::$salario;
	}
}

$tiago = new Funcionario();
$salario_tiago = &$tiago->getSalario();

var_dump($salario_tiago); // Exibirá 2000.00

$salario_tiago = 4000.00;

var_dump($salario_tiago); // Exibirá 4000.00
var_dump($tiago->getSalario()); // Exibirá 4000.00

?>

Primeiramente note que o operador de referência (&) está presente na chamada do método e na declaração do mesmo, isto é necessário, observe nas linhas 7 e 14.

Agora observe o funcionamento da teoria: o método getSalario() retorna o valor da propriedade privada $salario (o fato da propriedade ser estática não influencia nosso resultado), até ai tudo bem, mas note que ele não retorna somente o valor, mas retorna a referência do valor (daí o porque do ponteiro ser implícito), tornando possível modificar o valor não só da variável $salario_tiago, mas o valor da propriedade salário, ao mesmo tempo! veja na linha 18 onde estou alterando o valor para 4000.00, ao contrário de 2000.00 que estava anteriormente.

Assim tanto o valor da variável $salario_tiago, quanto o valor da propriedade $salario foram modificados =)

Muito interessante não?

Parte V: Referências a Objetos

Se você tentar utilizar algo como no código abaixo:

<?php

$tiago = &new Funcionario();

?>

O PHP irá produzir um erro E_STRICT porque desde a versão 5 ele já retorna por padrão uma referência do objeto a uma variável, ou seja o objeto Funcionario está em um determinado lugar da memória, e a variável $tiago já faz por natureza referência a este objeto. Assim declare um objeto normalmente, que o PHP já está otimizando a memória por default.

Referências do post:

Então é isso gente!

Abraços,

Tiago.

6 Comments

Add a Comment

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *