Laravel Release Update 9.32

marciopolicarpo

Marcio Policarpo

Posted on October 4, 2022

Laravel Release Update 9.32

Foi liberado em 28/09 o release 9.32 do Laravel.

A grande novidade deste release é a inclusão do helper Benchmark.

Com ele é possível medir o tempo de execução de qualquer processo dentro da aplicação de forma isolada, bastando para isso adicionar a referência use Illuminate\Support\Benchmark; na classe onde a análise será feita.


A classe Benchmark possui apenas dois métodos estáticos a saber:

public static function measure(Closure|array $benchmarkables, int $iterations = 1): array|float
Enter fullscreen mode Exit fullscreen mode
public static function dd(Closure|array $benchmarkables, int $iterations = 1): void
Enter fullscreen mode Exit fullscreen mode

Ambos recebem dois parâmetros:

  • $benchmarkables: array de funções para análise do tempo de processamento

  • $iterations: inteiro que indica a quantidade de iterações que serão aplicadas às funções do parâmetro anterior. Este parâmetro é opcional.

O método measure retorna um array com o tempo de cada função executada. Já o método dd, como o próprio nome diz, executa um dd (dump and die) comando bem comum em PHP geralmente utilizado para mostrar o valor de uma variável na camada de apresentação.

Testando

Para efeitos didáticos, vamos montar um exemplo simples onde consultaremos um cliente através do seu ID, utilizando 5 abordagens distintas.

⚠️ Conhecimento prévio sobre aplicações Laravel (criação, configuração e execução) é requerido.

As consultas serão feitas em uma tabela que possui 1037 registros, através de uma contoller chamada CustomerController. Apesar do pouco volume de informações, ressalto que a máquina onde os testes serão executados não possui uma performance elevada, equilibrando os resultados.

Migração

O arquivo de migração abaixo dará uma noção da estrutura da tabela de clientes, ajudando a compreender melhor o ambiente utilizado nos testes.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained();
            $table->string('last_name');
            $table->string('first_name');
            $table->string('email')->nullable();
            $table->string('phone', 30)->nullable();
            $table->string('street');
            $table->string('city');
            $table->string('building_number', 30);
            $table->string('country');
            $table->string('post_code');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('customers');
    }
};

Enter fullscreen mode Exit fullscreen mode

Rota

Vamos editar o arquivo de rotas de api (\routes\api.php) criando uma nova rota e adicionando a referência para a controller CustomerController que criaremos em breve:

Route::get('/{id}/show', [CustomerController::class, 'show']);
Enter fullscreen mode Exit fullscreen mode

E a referência para a controller:

use App\Http\Controllers\CustomerController;
Enter fullscreen mode Exit fullscreen mode

Controller

Nossa controller terá apenas um método responsável por consultar o cliente de acordo com o ID informado.

Abaixo como a classe deve se parecer:

<?php

namespace App\Http\Controllers;

use App\Models\Customer;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Http\Request;
use Illuminate\Support\Benchmark;
use Illuminate\Support\Facades\DB;

class CustomerController extends Controller
{
    public function show(int $id) 
    {        
        $customer = Customer::find($id);
        $result = Benchmark::measure(
            [
                'Scenario 1' => fn() => Customer::find($id),
                'Scenario 2' => fn() => Customer::where('id', ($id))->get(),
                'Scenario 3' => fn() => DB::table('customers')->where('id', $id)->first(),
                'Scenario 4' => fn() => DB::table('customers')->where('id', $id)->get(),
                'Scenario 5' => fn() => DB::select('select * from customers where id = ?', [$id])
            ], 10);

        if ($customer) {
            return response()->json([
                'time' => $result,
                'data' => $customer]);
        } else {            
            return response()->json(['message' => 'Customer not found'], 404);
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Perceba que à frente de cada funções adicionei um álias: 'Scenario 1', 'Scenario 2', etc.

Esse álias, apesar de opcional, ajudará bastante a identificar qual tempo refere-se a qual função analisada.

Testando

Assim que a aplicação estiver executando vamos fazer uma chamada à rota que configuramos anteriormente e informar um código para pesquisar o cliente.


Explicando

Cenário 1

A consulta realizada neste cenário é a mais básica, onde utilizamos o próprio modelo para buscar o cliente através da chave primária com o método find.

Apesar do tempo não ser um dos melhores, há que se frisar que existe um custo de processamento para converter o resultado no modelo Customer.

Cenário 2

Neste o tempo melhorou um pouquinho em relação ao cenário anterior. A diferença é que passamos a coluna id diretamente para consultar.

Acredito que se a coluna id não fosse indexada o resultado seria significativamente pior.

E neste cenário ainda temos o custo de conversão do resultado da consulta no modelo Customer.

Cenário 3

A partir deste cenário ficamos mais próximos do banco de dados realizando consultas consideradas mais 'brutas'.

Por conta dessa abordagem note que os tempos de retorno são melhores justamente por eliminarmos o processamento feito na camada de abstração do Eloquent ORM.

Cenário 4

A única diferença em relação ao cenário anterior é que estamos utilizando o método get() ao invés do método first().

Ocorre que ao executarmos o método first() há um processamento adicional para retornar somente o primeiro registro da consulta o que não acontece com o método get().

Cenário 5

Na maioria dos testes este se mostrou o mais rápido de todos porque passamos uma consulta 'bruta' ao banco de dados filtrando o cliente pelo ID informado no parâmetro.

Apesar do tempo consideravelmente menor é importante lembrar que este tipo de consulta não se aplica a todas as situações possíveis.

Um bom exemplo onde o resultado poderia se apresentar mais produtivo, seriam as funções de agregação de dados (sum, max, count, etc) onde é menos custoso já trazer as consultas agrupadas ao invés de fazer um processamento adicional na aplicação.


Todos os testes foram executados 10 vezes, conforme informamos no parâmetro opcional $iterations do método estático measure(). Então, o resultado mostrado refere-se ao tempo médio das 10 tentativas realizadas.

Ao suprimir este parâmetro cada uma das funções será executada apenas uma vez.


Adições

Este release também trouxe outras funcionalidades:

Caminho do arquivo na função 'dd'

A partir deste release, sempre que utilizarmos a função dd (dump and die) o caminho completo do arquivo também fará parte do resultado

(mais detalhes aqui)


Encriptar e decriptar arquivos .env

Foram adicionados dois novos comandos ao script artisan, com a finalidade de gerar um arquivo encriptado a partir do arquivo '.env', bem como decriptá-lo.

Para encriptar: php artisan env:encrypt

Para decriptar: php artisan env:decrypt

Lembrando que os comandos devem ser executados utilizando o terminal de sua preferência a partir do diretório raiz da aplicação.

(mais detalhes aqui)


A lista completa das novas funcionalidades deste release, bem como correções e melhoramentos, pode ser encontrada aqui (em inglês).

Até breve!
😎

💖 💪 🙅 🚩
marciopolicarpo
Marcio Policarpo

Posted on October 4, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Laravel Release Update 9.32
laravel Laravel Release Update 9.32

October 4, 2022