
Quanto às micro otimizações do PHP, substituindo aspas duplas por aspas simples, há tantas cópias quebradas que é bastante problemático criar um novo fluxo. Mas vou tentar.
Neste artigo, haverá apenas uma referência, onde estaria sem ela, e a ênfase principal está na análise de como ela é organizada.
Isenção de responsabilidade
- Tudo descrito abaixo é, na maioria das vezes, economizando nanossegundos e, na prática, não fará nada além de perder o tempo perdido com essa microoptimização. Isto é especialmente verdade para "otimizações" do tempo de compilação.
- Cortarei o código e a saída ao máximo, deixando apenas a essência.
- Ao escrever um artigo, usei o PHP 7.2
Introdutório necessário
Uma cadeia de caracteres entre aspas duplas
no estágio de compilação é processada de maneira ligeiramente diferente de uma cadeia de caracteres entre aspas simples.
Aspas simples serão analisadas da seguinte maneira:
statement -> expr -> scalar -> dereferencable_scalar -> T_CONSTANT_ENCAPSED_STRING
Dobro assim:
statement -> expr -> scalar -> '"' encaps_list '"' -> , ,
Em artigos sobre micro otimizações do PHP, muitas vezes há conselhos para não usar a
impressão , pois é mais lenta que o
eco . Vamos ver como eles são classificados.
Analisando
eco :
statement -> T_ECHO echo_expr_list -> echo_expr_list -> echo_expr -> expr
Análise de
impressão :
statement -> expr -> T_PRINT expr -> expr ( )
I.e. em geral, sim, o
eco é detectado um passo mais cedo e esse passo, deve-se notar, é bastante difícil.
Para não acentuar a atenção novamente durante o artigo, teremos em mente que, no estágio de compilação, as aspas duplas perdem um único e a
impressão perde o
eco . Além disso, não devemos esquecer que, na pior das hipóteses, trata-se de nanossegundos.
Bem, para não se levantar duas vezes. Aqui estão as funções diff, compilando
print e
echo :
1 - void zend_compile_print(znode *result, zend_ast *ast) 1 + void zend_compile_echo(zend_ast *ast) 2 2 { 3 3 zend_op *opline; 4 4 zend_ast *expr_ast = ast->child[0]; 5 5 6 6 znode expr_node; 7 7 zend_compile_expr(&expr_node, expr_ast); 8 8 9 9 opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL); 10 - opline->extended_value = 1; 11 - 12 - result->op_type = IS_CONST; 13 - ZVAL_LONG(&result->u.constant, 1); 10 + opline->extended_value = 0; 14 11 }
Bem, você entende - eles são idênticos em funcionalidade, mas a
impressão também retorna uma constante igual a 1. Penso neste tópico com a
impressão, você pode fechar e esquecê-lo para sempre.
Linha simples, sem frescuras
Strings
echo 'Some string';
e
echo "Some string";
será dividido quase de forma idêntica em 2 tokens (aviso de isenção de responsabilidade P2).
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE/T_CONSTANT_ENCAPSED_STRING: "Some string"
Além disso, para aspas simples sempre haverá T_CONSTANT_ENCAPSED_STRING, e para aspas duplas, quando for necessário. Se houver um espaço na linha, então T_ENCAPSED_AND_WHITESPACE.
Os códigos de operação serão simples de desonrar e absolutamente idênticos:
line
Conclusões
Se você deseja salvar alguns ciclos do processador no estágio de compilação, use seqüências de caracteres simples para seqüências de caracteres constantes.
Linha dinâmica
Existem 4 opções.
echo "Hello $name! Have a nice day!"; echo 'Hello '.$name.'! Have a nice day!'; echo 'Hello ', $name, '! Have a nice day!'; printf ('Hello %s! Have a nice day!', $name);
Para a primeira opção:
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE: Hello T_VARIABLE: $name T_ENCAPSED_AND_WHITESPACE: ! Have a nice day!
Para o segundo (para o terceiro também, somente em vez de períodos haverá vírgulas):
T_ECHO: echo T_CONSTANT_ENCAPSED_STRING: 'Hello ' string: . T_VARIABLE: $name string: . T_CONSTANT_ENCAPSED_STRING: '! Have a nice day!'
Pela quarta:
T_STRING: printf T_CONSTANT_ENCAPSED_STRING: 'Hello %s! Have a nice day!' string: , T_VARIABLE: $name
Mas com opcodes tudo será muito mais divertido.
Primeiro:
echo "Hello $name! Have a nice day!"; line
Segundo:
echo 'Hello '.$name.'! Have a nice day!'; line
Terceiro:
echo 'Hello ', $name, '! Have a nice day!'; line
Quarto:
printf ('Hello %s! Have a nice day!', $name); line
O senso comum nos diz que a opção com `printf` perderá velocidade nos três primeiros (especialmente porque no final ainda existe o mesmo ECHO), portanto deixaremos para tarefas em que a formatação é necessária e não nos lembraremos mais deste artigo.
Parece que a terceira opção é a mais rápida - imprimir três linhas consecutivas sem concatenações, ROPEs estranhas e a criação de variáveis adicionais. Mas não é tão simples. A função de impressão no PHP certamente não é a Rocket Science, mas não é, de forma alguma, uma fonte banal de C-
shny . Quem se
importa - a bola se desenrola começando com
php_output_write no
arquivo main / output.c .
CONCAT. Tudo é simples aqui - convertemos, se necessário, os argumentos em strings e criamos um novo
zend_string usando o
memcpy rápido. O único aspecto negativo é que, com uma longa cadeia de concatenações para cada operação, novas linhas serão criadas deslocando os mesmos bytes de um lugar para outro.
Mas com ROPE_INIT, ROPE_ADD e ROPE_END tudo é muito mais interessante. Siga as mãos:
- ROPE_INIT (ext = 3, retorno = ~ 3, operandos = 'Hello +')
Alocamos a “corda” de três slots (ext), colocamos a string 'Hello +' (operandos) no slot 0 e retornamos a variável temporária ~ 3 (return) que contém a “corda”. - ROPE_ADD (ext = 1, retorno = ~ 3, operandos = ~ 3 ,! 0)
Colocamos no espaço 1 (ext) da “corda” ~ 3 (operandos) a corda 'Vasya' obtida da variável! 0 (operandos) e retornamos a “corda” ~ 3 (retorno). - ROPE_END (ext = 2, retorno = ~ 2, operandos = ~ 3, '% 21 + Tenha + um + bom + dia% 21')
Colocamos a linha '% 21 + Have + a + nice + day% 21' (operandos) no slot 2 (ext), após o qual criamos um zend_string do tamanho necessário e copiamos todos os slots de “corda” nele, com o mesmo memcpy .
Separadamente, é importante notar que, no caso de constantes e variáveis temporárias, os links para os dados serão colocados nos slots e não haverá cópia desnecessária.
Na minha opinião, bastante elegante. :)
Vamos avaliar. Como dados de origem, pegamos o arquivo
zend_vm_execute.h (IMHO, isso será verdade) por 71 mil linhas e o imprimimos de 100 maneiras para 100 passes, diminuindo o mínimo e o máximo (cada medição começou 10 vezes, escolhendo a opção mais comum):
<?php $file = explode("\n", file_get_contents("C:\projects\C\php-src\Zend\zend_vm_execute.h")); $out = []; for ($c = 0; $c < 100; $c++) { $start = microtime(true); ob_start(); $i = 0; foreach ($file as $line) { $i++;
O que medimos | Tempo médio em segundos |
---|
"Corda" | 0,0129 |
Vários ECHO | 0,0135 |
Concatenação | 0,0158 |
printf , para completar | 0,0245 |
Conclusões
- Para cadeias de caracteres com substituição simples, de repente, aspas duplas são mais ideais que aspas simples com concatenação. E quanto mais longas as linhas forem usadas, maior será o ganho.
- Argumentos separados por vírgulas ... Existem muitas nuances. Por medição, é mais rápido que a concatenação e mais lento que o “cabo”, mas há muitas “variáveis” associadas à entrada / saída.
Conclusão
É difícil para mim encontrar uma situação em que possa surgir a necessidade de tais micro-otimizações. Ao escolher essa ou aquela abordagem, é mais razoável ser guiado por outros princípios - por exemplo, legibilidade do código ou estilo de codificação adotado pela sua empresa.
Quanto a mim, pessoalmente, não gosto da abordagem de concatenação por causa da aparência vyrviglazny, embora em alguns casos isso possa ser justificado.
PS Se esse tipo de análise é interessante - me avise - há muito mais que nem sempre é inequívoco e óbvio: uma variedade de objetos do VS, para cada VS enquanto VS para, sua opção ... :)
Uma pequena explicação da leitura dos comentários
A sintaxe HEREDOC e as "strings complexas" (onde as variáveis estão entre chaves) são as mesmas strings de aspas duplas e compilam exatamente da mesma maneira.
Uma mistura de PHP com HTML como este:
<?php $name = 'Vasya';?>Hello <?=$name?>! Have a nice day!
Isso é apenas 3
ecos seguidos.