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,
oi professor, tudo bem.
sou iniciante em php e estou com muita dificuldade queria que o senhor com urgência atendesse o meu requisito, pois fui inserida em uma criação de um sistema de login e queria algo seguro na leitura da senhas.
incluindo banco de dados para a passagem desta informações, porém fiz o formulário em html e a passagem deste dados pelo método post,ai tudo bem mais não sei como fazer para que o usuário que digitar seu login , senha e por fim a senha aleatória da página essa que pra mim esta complexa.pois ao digita-lá esta senha aleatória o usuário tenha um bloqueio para não conseguir acessar a próxima página,caso ele tenha digitado a senha aleatória incorreta .mas caso for correta ele sim consiga ter acesso permitido a página.
Priscila
oi professor, tudo bem.
sou iniciante em php e estou com muita dificuldade queria que o senhor com urgência atendesse o meu requisito, pois fui inserida em uma criação de um sistema de login e queria algo seguro na leitura da senhas.
incluindo banco de dados para a passagem desta informações, porém fiz o formulário em html e a passagem deste dados pelo método post,ai tudo bem mais não sei como fazer para que o usuário que digitar seu login , senha e por fim a senha aleatória da página essa que pra mim esta complexa.pois ao digita-lá esta senha aleatória o usuário tenha um bloqueio para não conseguir acessar a próxima página,caso ele tenha digitado a senha aleatória incorreta .mas caso for correta ele sim consiga ter acesso permitido a página.
tratasse da mesma pessoa.
Oi Priscila, bom dia!
Pelo que eu entendi você quer limitar o número de tentativas que o usuário terá para fazer o login.
Dê uma olhada nisso: https://pt.stackoverflow.com/questions/133397/limitar-tentativas-de-login-por-tempo-e-quantidade
Como você é iniciante, sugiro que fale com o pessoal do seu grupo, pois esta tarefa não é tão trivial assim.
se puder professor mande pra mim um de sua autoria.
Assim que sobrar um tempinho vou fazer um post sobre sistemas de login 😉