São variáveis ​​estáticas estranhas no PHP

Isenção de responsabilidade: este artigo não revelará nenhuma revelação para você e não abrirá o terceiro olho, mas permitirá que você entenda a pergunta não tão óbvia com mais detalhes. Pelo menos quando eu escrevi, ela me ajudou nisso. Se você é um lobo experiente em php, então você não pode lê-lo, acho que não fará mal a pessoas experientes passarem por seus olhos, atualizá-las na memória, por assim dizer, o resto será normal.


Então ...


Variáveis ​​estáticas no php são um tipo especial de variável que é declarada usando a palavra-chave estática .


static $foo = 3; 

Eles diferem das variáveis ​​comuns nesse sentido (mais adiante no artigo, esses pontos serão considerados com mais detalhes):


  1. somente constantes e expressões constantes podem ser atribuídas
  2. o tempo de vida de uma variável estática não se limita ao tempo de vida do escopo em que foi declarada
  3. pode ser definido no script apenas uma vez
  4. não destruído até o final do script

Agora em ordem.


1. Somente constantes e expressões constantes podem ser atribuídas


Isso significa que o resultado da operação de qualquer função ou método não pode ser atribuído a uma variável estática ou, em geral, qualquer coisa que ainda não seja conhecida no estágio de compilação. Ou seja, esse anúncio não funcionará


 static $var = foo(); 

mas é bem possível


 static $var = 'some str'; static $varInt = 3 + 5; 

2. O tempo de vida de uma variável estática não se limita ao tempo de vida do escopo em que é declarada


Vou tentar explicar o que eu quis dizer aqui. Talvez eu faça algumas imprecisões na terminologia, mas tentarei transmitir a essência com a maior precisão possível. Compare com uma variável regular. Se uma variável é declarada dentro de uma função, por padrão é uma variável local, ou seja, é declarada no escopo local (escopo desta função). Nesse caso, o contexto dessa função será o escopo local. Após a função ter trabalhado e retornado o resultado, seu escopo ou contexto, com todas as variáveis ​​dentro dela, serão destruídos.


Se declararmos uma variável estática dentro da função, ela também será declarada no escopo local, mas seu contexto não será o escopo local, mas a própria função.


(Além disso, o momento mais difícil de explicar, passo apenas a essência, sem detalhes, como as funções são declaradas no php, quanta memória é alocada a eles e o que está nessa memória). Acontece que, quando uma função é chamada, o intérprete cria um escopo local para ela; é nele que todas as variáveis ​​e funções locais são declaradas e anexadas a ela como em seu contexto. Ao declarar uma variável no escopo local usando estática, a própria função é atribuída a essa variável como um contexto, e essa variável existirá enquanto a própria função existir. Isso é algo como js quando uma função é um objeto no qual você pode atribuir propriedades e métodos arbitrários. Aqui, também, apenas uma função em php é um objeto não para php, mas para uma linguagem inferior.


 function echoStaticVar() { static $var = 0; $var++; var_dump($var); }; echoStaticVar(); //1 echoStaticVar(); //2 echoStaticVar(); //3 

Pode-se observar que, após o término da função, o coletor não destrói a variável $ var, como faria com uma variável regular.


E aqui está um exemplo que mostra claramente que uma variável estática pertence a uma função (ou ela é armazenada em uma função ou seu contexto é uma função, então, desculpe, não sei como nomeá-la corretamente).


 $one = function ($i) { static $var = 0; $var += $i; var_dump($var); }; $two = $one; $one(1); //1 $one(5); //6 $one(5); //11 $two(5); //16 $two(5); //21 

Tudo funciona como esperado, porque ao atribuir $ dois = $ um; a função em si não é copiada, mas simplesmente essas duas variáveis ​​se referem à mesma área de memória. Por conseguinte, a variável estática $ var será uma para $ one e $ two


Mudamos um pouco o exemplo, ou seja, não atribuímos, mas clonamos


 // $two = $one; // $two = clone($one); 

 $one = function ($i) { static $var = 0; $var += $i; var_dump($var); }; $two = clone($one); $one(1); //1 $one(5); //6 $one(5); //11 $two(5); //5 $two(5); //10 

Agora, descobriu-se que $ one e $ two não se referem à mesma função com uma variável estática $ var, mas a duas funções diferentes que se encontram em áreas de memória diferentes e cada uma tem sua própria variável estática $ var. Este não é um ponto particularmente óbvio, então você pode tropeçar nele, se você certamente escrever código em um estilo procedural, o que provavelmente já é considerado uma má forma, mas isso não é exato).


O que você pode fazer com isso é um exemplo clássico de um contador de chamadas de função.
Mas em conexão com a disseminação do OOP dessa forma, as variáveis ​​estáticas são raras, pois basicamente você precisa operar com classes e métodos (escreverei um artigo separado sobre a implementação da estática nelas)


3. pode ser definido no script apenas uma vez


Isso significa que se uma variável estática já estiver declarada e um valor for atribuído a ela, as atribuições subsequentes não substituirão o valor já atribuído, mas retornarão a existente.


 function staticVar($i) { static $var = 0; $var += $i; var_dump($var); }; staticVar(1); //1 staticVar(5); //6 staticVar(5); //11 

Pode-se observar que, se a variável estática $ var cada vez tivesse um valor reatribuído, sempre obteríamos o resultado 1. Mas, como não é reescrita quando reatribuída, obtemos o que obtemos.
É verdade que há uma coisa que pode estragar tudo. Dentro da estrutura de uma função (mais precisamente, na primeira vez em que a função é chamada), essa variável pode ser reescrita quantas vezes você quiser (posteriormente, tudo funcionará como indicado). Esse comportamento me pareceu estranho e engraçado, especialmente se você brinca com exemplos.


 function staticVar($i) { static $var = 0; static $var = 5; $var += $i; var_dump($var); }; staticVar(1); //6 staticVar(5); //11 staticVar(5); //16 

Aqui a variável $ var na primeira chamada para a função staticVar em sua primeira linha foi atribuída e substituída na segunda linha. Mas já em outras ligações, nem na primeira nem na segunda linha, ela foi redesignada, mas retornou o que já estava na ligação anterior


 function staticVar($i) { static $var = 0; // static $var = 5; //    $var += $i; static $var = 0; //    var_dump($var); }; staticVar(1); //1 staticVar(5); //6 staticVar(5); //11 

Mesmo estranho na primeira chamada de staticVar na primeira linha, ele foi atribuído, depois na segunda linha foi reatribuído (mas sem êxito), em seguida, uma ação de adição foi executada com ele e, depois disso, ao tentar reatribuir mesmo na primeira chamada de função, ele retornou o que já estava em o significado dela.


 function staticVarWrong($i) { static $var = 0; static $var = 5; $var += $i; var_dump($var); }; //  staticVarWrong(1); //6 staticVarWrong(5); //11 staticVarWrong(5); //16 function staticVarRight($i) { static $var = 0; static $var = 5; $var += $i; static $var = 0; //    var_dump($var); }; //  staticVarRight(1); //1 staticVarRight(5); //6 staticVarRight(5); //11 

Ou seja, acontece quase nos mesmos métodos, comportamento diferente. Além disso, com base na descrição de como as variáveis ​​estáticas devem se comportar, o resultado correto é obtido no staticVarRight . No staticVarWrong, verifica - se (com base no comportamento da função) que na segunda linha da função a variável foi redefinida.
Isso me divertiu bastante.


4. não são destruídos até o final do script


Não vejo muito sentido em explicar esse ponto, principalmente porque tudo está claro nos exemplos. Enquanto o script está em execução e enquanto há uma função para a qual uma variável estática é declarada, essa variável existe.


Conforme planejado, este é o primeiro artigo sobre estática , antes da OOP, campos estáticos, métodos.
Bem, é claro, se for pelo menos alguém estará interessado e não será difícil culpar.

Source: https://habr.com/ru/post/pt467489/


All Articles