O Segredo da Barra Invertida no PHP: Deixe seu Código mais Rápido com Esse Truque!

Você já se pegou perguntando por que alguns desenvolvedores colocam barras invertidas () antes de suas chamadas de função no PHP? Essa técnica, que parece estranha à primeira vista, é, na verdade, um truque para acelerar o desempenho do seu aplicativo! Se você quer descobrir como isso funciona, vem comigo que eu vou te contar tudo!

A Mágica dos Namespaces no PHP Desde a versão 5.3 do PHP, temos uma funcionalidade muito útil chamada "namespaces", que serve para organizar elementos como classes e funções dentro de um aplicativo, de uma maneira que lembra bastante a estrutura de pastas do seu computador. Ao usar namespaces, você pode evitar conflitos de nomes e manter seu código bem organizado.

Por exemplo, se você quer acessar uma classe dentro de um namespace específico, você inicia com o namespace raiz () seguido de todos os namespaces "pais" separados por . Dessa maneira, o interpretador sabe exatamente onde encontrar a classe que você está chamando:

$user = new \App\Model\User();

A Arte de Usar a Barra Invertida Assim como classes, funções também podem ser agrupadas em namespaces. Imagine que você tem uma função hello() no namespace App\Model, você a chamaria assim:

\App\Model\hello();

Quando você coloca uma barra invertida antes de uma chamada de função, está indicando ao interpretador para buscar essa função diretamente no namespace raiz, onde, por acaso, a maioria das funções integradas do PHP estão localizadas.

Desvendando o Opcode Vou te contar um segredinho agora: o PHP traduz seu código para uma linguagem intermediária chamada "opcode" antes de executá-lo. Ao analisar o opcode gerado pelo seu código, você pode entender melhor como o PHP está manipulando suas instruções.

Usando ferramentas como 3v4l, é possível converter suas chamadas de função para opcode e observar a diferença que uma simples barra invertida pode fazer. Sem entrar muito em detalhes técnicos, a principal vantagem de usar a barra invertida é que ela evita uma busca desnecessária pelo namespace atual, economizando tempo e recursos valiosos.

Vantagens Adicionais da Otimização E aí que a coisa fica ainda mais interessante! Algumas funções embutidas do PHP podem ter seu desempenho ainda mais potencializado com a adição da barra invertida, já que ela permite ao interpretador substituir diretamente a chamada da função pelo opcode associado. Funções como strlen(), count() e in_array() são alguns exemplos que se beneficiam bastante dessa otimização.

Conclusão: Um Pequeno Truque, Grandes Resultados A princípio, adicionar uma barra invertida às chamadas de função pode parecer apenas uma micro-otimização. Porém, considerando a quantidade de chamadas de função que acontecem a cada solicitação em sua aplicação, esses milissegundos economizados podem se acumular rapidamente!

Não estou sugerindo que você saia mudando todas as chamadas de função em seus projetos agora (embora existam ferramentas que podem ajudar com isso 😉), mas acredito que é muito útil entender as nuances e os recursos disponíveis em sua linguagem de programação. Espero que você tenha aprendido algo novo e útil hoje, e que possa usar esse conhecimento para criar códigos ainda mais rápidos e eficientes!

Este artigo foi inspirado pelo trabalho de Jeroen Deviaene. Você pode ler o artigo original em deviaene.eu

Vi um artigo falando que em 17.000 chamadas de função o cara ganhou 0.1ms.

Acho bem irrelevante pela trabalheira e pela pessima legibilidade do código...

Funções como strlen(), count() e in_array() são alguns exemplos que se beneficiam bastante dessa otimização.

Só de curiosidade, fiz um teste rápido usando a ferramenta phpbench para medir os tempos.

O teste foi bem simples, só chamei strlen e in_array com e sem a barra, passando os mesmos argumentos:

class TimeConsumerBench {
    private $s;
    private $v;
    public function __construct() {
        $this->s = 'kjfasdsjfdsaklfjaksjfklasdjfjasdfjasdlfjasjfasldçjfasd';
        $this->v = range(1, 1000); // array com os números de 1 a 1000
    }

    public function benchStrlenSemBarra() {
        strlen($this->s);
    }
    public function benchStrlenComBarra() {
        \strlen($this->s);
    }

    public function benchInArraySemBarra() {
        in_array(2000, $this->v);
    }
    public function benchInArrayComBarra() {
        \in_array(2000, $this->v);
    }
}

Para montar todo o teste, basta seguir o tutorial básico da documentação (apenas adaptei dali).

Fiz o teste rodando 10 iterações para cada função, sendo que a cada iteração ela é executada 1 milhão de vezes. A linha de comando usada foi:

./vendor/bin/phpbench run tests/Benchmark --report=aggregate --iterations=10 --revs=1000000

Os testes foram feitos com PHP 8.1.2, phpbench 1.2.14, em uma máquina com Ubuntu 22.04.3, processador 11th Gen Intel® Core™ i5-1145G7 2.60GHz, 8 núcleos. O resultado foi:

    benchStrlenSemBarra.....................I9 - Mo0.022μs (±1.26%)
    benchStrlenComBarra.....................I9 - Mo0.015μs (±1.83%)
    benchInArraySemBarra....................I9 - Mo0.625μs (±3.06%)
    benchInArrayComBarra....................I9 - Mo0.621μs (±0.79%)

Subjects: 4, Assertions: 0, Failures: 0, Errors: 0
+-------------------+----------------------+-----+---------+-----+-----------+---------+--------+
| benchmark         | subject              | set | revs    | its | mem_peak  | mode    | rstdev |
+-------------------+----------------------+-----+---------+-----+-----------+---------+--------+
| TimeConsumerBench | benchStrlenSemBarra  |     | 1000000 | 10  | 707.240kb | 0.022μs | ±1.26% |
| TimeConsumerBench | benchStrlenComBarra  |     | 1000000 | 10  | 707.240kb | 0.015μs | ±1.83% |
| TimeConsumerBench | benchInArraySemBarra |     | 1000000 | 10  | 707.240kb | 0.625μs | ±3.06% |
| TimeConsumerBench | benchInArrayComBarra |     | 1000000 | 10  | 707.240kb | 0.621μs | ±0.79% |
+-------------------+----------------------+-----+---------+-----+-----------+---------+--------+

No caso de strlen, sem a barra o tempo médio foi de 0.022μs (0,022 microssegundos, ou 22 nanossegundos, ou 0,000000022 segundos). Ou seja, 22 bilionésimos de segundo. Adicionando a barra, caiu para 15 nanossegundos. Sim, foi mais rápido, mas lembre-se que foram 10 iterações com 1 milhão de execuções cada (ou seja, cada uma foi executada 10 milhões de vezes).

No caso de in_array, o ganho foi menor ainda, apenas 4 nanossegundos mais rápido com a barra.

Então a menos que seu código seja executado milhões de vezes em um curto intervalo de tempo, ou o desempenho da aplicação seja extremamente crítico (a ponto de alguns nanossegundos fazerem a diferença), eu diria que o ganho em geral será não só imperceptível, como também insignificante.

Para mim, parece mais o típico caso de micro-otimização desnecessária. Em vez de sair colocando a barra em tudo, o ideal - como sempre - é fazer testes de stress adequados em condições reais (ou o mais próximo possível disso) e ver onde de fato estão os gargalos.