"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Aspas duplas demais ou não, eis a questão!

Aspas duplas demais ou não, eis a questão!

Publicado em 2024-08-27
Navegar:435

Recentemente ouvi novamente que o pessoal do PHP ainda fala sobre aspas simples versus aspas duplas e que usar aspas simples é apenas uma micro otimização, mas se você se acostumar a usar aspas simples o tempo todo, você economizará um monte de CPU ciclos!

"Tudo já foi dito, mas ainda não por todos" – Karl Valentin

É com esse espírito que estou escrevendo um artigo sobre o mesmo assunto que Nikita Popov escreveu há 12 anos (se você está lendo o artigo dele, pode parar de ler aqui).

Do que se trata a confusão?

PHP realiza interpolação de strings, na qual busca o uso de variáveis ​​em uma string e as substitui pelo valor da variável utilizada:

$juice = "apple";
echo "They drank some $juice juice.";
// will output: They drank some apple juice.

Este recurso é limitado a strings entre aspas duplas e heredoc. Usar aspas simples (ou nowdoc) produzirá um resultado diferente:

$juice = "apple";
echo 'They drank some $juice juice.';
// will output: They drank some $juice juice.

Veja só: o PHP não procurará variáveis ​​​​nessa string entre aspas. Então poderíamos começar a usar aspas simples em todos os lugares. Então as pessoas começaram a sugerir mudanças como esta ..

- $juice = "apple";
  $juice = 'apple';

.. porque será mais rápido e economizará vários ciclos de CPU com cada execução desse código porque o PHP não procura variáveis ​​​​em strings entre aspas simples (que são inexistentes no exemplo de qualquer maneira) e todos estão felizes, caso encerrado.

Caso encerrado?

Obviamente, há uma diferença no uso de aspas simples e aspas duplas, mas para entender o que está acontecendo, precisamos nos aprofundar um pouco mais.

Mesmo que o PHP seja uma linguagem interpretada, ele usa uma etapa de compilação na qual certas partes são executadas juntas para obter algo que a máquina virtual possa realmente executar, que são os opcodes. Então, como passamos do código-fonte PHP para os opcodes?

O lexer

O lexer verifica o arquivo de código-fonte e o divide em tokens. Um exemplo simples do que isso significa pode ser encontrado na documentação da função token_get_all(). Um código fonte PHP de apenas

T_OPEN_TAG (

Podemos ver isso em ação e brincar com isso neste trecho 3v4l.org.

O analisador

O analisador pega esses tokens e gera uma árvore de sintaxe abstrata a partir deles. Uma representação AST do exemplo acima fica assim quando representada como JSON:

{
  "data": [
    {
      "nodeType": "Stmt_Echo",
      "attributes": {
        "startLine": 1,
        "startTokenPos": 1,
        "startFilePos": 6,
        "endLine": 1,
        "endTokenPos": 4,
        "endFilePos": 13
      },
      "exprs": [
        {
          "nodeType": "Scalar_String",
          "attributes": {
            "startLine": 1,
            "startTokenPos": 3,
            "startFilePos": 11,
            "endLine": 1,
            "endTokenPos": 3,
            "endFilePos": 12,
            "kind": 2,
            "rawValue": "\"\""
          },
          "value": ""
        }
      ]
    }
  ]
}

Caso você queira brincar com isso também e ver como é o AST para outro código, encontrei https://phpast.com/ de Ryan Chandler e https://php-ast-viewer.com/ que ambos mostram o AST de um determinado trecho de código PHP.

O compilador

O compilador pega o AST e cria opcodes. Os opcodes são as coisas que a máquina virtual executa, é também o que será armazenado no OPcache se você tiver essa configuração e habilitada (o que eu recomendo fortemente).

Para visualizar os opcodes temos múltiplas opções (talvez mais, mas eu conheço essas três):

  1. use a extensão dumper lógico vulcan. Também está incluído em 3v4l.org
  2. use phpdbg -p script.php para despejar os opcodes
  3. ou use a configuração INI opcache.opt_debug_level para OPcache para fazer com que ele imprima os opcodes
    • um valor de 0x10000 gera opcodes antes da otimização
    • um valor de 0x20000 gera opcodes após a otimização
$ echo ' foo.php
$ php -dopcache.opt_debug_level=0x10000 foo.php
$_main:
...
0000 ECHO string("")
0001 RETURN int(1)

Hipótese

Voltando à ideia inicial de economizar ciclos de CPU ao usar aspas simples versus aspas duplas, acho que todos concordamos que isso só seria verdade se o PHP avaliasse essas strings em tempo de execução para cada solicitação.

O que acontece em tempo de execução?

Então vamos ver quais opcodes o PHP cria para as duas versões diferentes.

Aspas duplas:

0000 ECHO string("apple")
0001 RETURN int(1)

vs. aspas simples:

0000 ECHO string("apple")
0001 RETURN int(1)

Ei, espere, algo estranho aconteceu. Isso parece idêntico! Para onde foi minha micro otimização?

Bem, talvez, apenas talvez a implementação do manipulador de opcode ECHO analise a string fornecida, embora não haja nenhum marcador ou algo mais que diga para fazer isso ... hmm ?

Vamos tentar uma abordagem diferente e ver o que o lexer faz para esses dois casos:

Aspas duplas:

T_OPEN_TAG (

vs. aspas simples:

Line 1: T_OPEN_TAG (

Os tokens ainda distinguem entre aspas duplas e simples, mas verificar o AST nos dará um resultado idêntico para ambos os casos - a única diferença é o rawValue nos atributos do nó Scalar_String, que ainda possui aspas simples/duplas, mas o valor usa aspas duplas em ambos os casos.

Nova hipótese

Será que a interpolação de strings é realmente feita em tempo de compilação?

Vamos verificar com um exemplo um pouco mais "sofisticado":

Os tokens para este arquivo são:

T_OPEN_TAG (

Veja os dois últimos tokens! A interpolação de strings é tratada no lexer e, como tal, é uma questão de tempo de compilação e não tem nada a ver com tempo de execução.

Too double quote or not, that

Para completar, vamos dar uma olhada nos opcodes gerados por isso (após a otimização, usando 0x20000):

0000 ASSIGN CV0($juice) string("apple")
0001 T2 = FAST_CONCAT string("juice: ") CV0($juice)
0002 ECHO T2
0003 RETURN int(1)

Este é um código de operação diferente do que tínhamos em nosso simples

Vá direto ao ponto: devo concatenar ou interpolar?

Vamos dar uma olhada nessas três versões diferentes:

  • a primeira versão está usando interpolação de string
  • o segundo é usar uma separação por vírgula (que AFAIK só funciona com eco e não com atribuição de variáveis ​​​​ou qualquer outra coisa)
  • e a terceira opção usa concatenação de strings

O primeiro opcode atribui a string "apple" à variável $juice:

0000 ASSIGN CV0($juice) string("apple")

A primeira versão (interpolação de strings) usa uma corda como estrutura de dados subjacente, que é otimizada para fazer o mínimo possível de cópias de strings.

0001 T2 = ROPE_INIT 4 string("juice: ")
0002 T2 = ROPE_ADD 1 T2 CV0($juice)
0003 T2 = ROPE_ADD 2 T2 string(" ")
0004 T1 = ROPE_END 3 T2 CV0($juice)
0005 ECHO T1

A segunda versão é a mais eficaz em termos de memória, pois não cria uma representação de string intermediária. Em vez disso, ele faz várias chamadas para o ECHO, o que é uma chamada de bloqueio do ponto de vista de E/S, portanto, dependendo do seu caso de uso, isso pode ser uma desvantagem.

0006 ECHO string("juice: ")
0007 ECHO CV0($juice)
0008 ECHO string(" ")
0009 ECHO CV0($juice)

A terceira versão usa CONCAT/FAST_CONCAT para criar uma representação de string intermediária e, como tal, pode usar mais memória do que a versão em corda.

0010 T1 = CONCAT string("juice: ") CV0($juice)
0011 T2 = FAST_CONCAT T1 string(" ")
0012 T1 = CONCAT T2 CV0($juice)
0013 ECHO T1

Então... qual é a coisa certa a fazer aqui e por que é interpolação de strings?

A interpolação de string usa um FAST_CONCAT no caso de echo "juice: $juice"; ou opcodes ROPE_* altamente otimizados no caso de echo "juice: $juice $juice";, mas o mais importante é que comunica a intenção claramente e nada disso foi um gargalo em qualquer um dos aplicativos PHP com os quais trabalhei até agora, então nada disso realmente importa.

TLDR

A interpolação de strings é uma questão de tempo de compilação. Concedido, sem o OPcache o lexer terá que verificar as variáveis ​​​​usadas em strings entre aspas duplas em cada solicitação, mesmo que não haja nenhuma, diminuindo os ciclos de CPU, mas honestamente: o problema não são as strings entre aspas duplas, mas não usando o OPcache!

No entanto, há uma ressalva: PHP até 4 (e acredito que mesmo incluindo 5.0 e talvez até 5.1, não sei) fazia interpolação de strings em tempo de execução, então usando essas versões... hmm, acho que se alguém realmente ainda usa PHP 5, o mesmo que acima se aplica: O problema não são as strings entre aspas duplas, mas o uso de uma versão desatualizada do PHP.

Conselho final

Atualize para a versão mais recente do PHP, habilite o OPcache e viva feliz para sempre!

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/realflowcontrol/too-double-quote-or-not-thats-the-question-78l?1 Se houver alguma violação, entre em contato com [email protected] para excluir isto
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3