Guia Definitivo: Como Debugar PHP 5, 7 e 8 em Produção Como um Sênior
Blog

Guia Definitivo: Como Debugar PHP 5, 7 e 8 em Produção Como um Sênior

Mauro Rocha Tavares
11 min de leitura

O texto ficou um pouco grande porque inclui alguns exemplos de código, caso alguém precise. Espero que te ajude a sobreviver e mizar algumas horas ou ter mais horas para descançar.

Trabalhar com múltiplas versões de PHP simultaneamente é como ser um arqueólogo digital – você precisa conhecer as ferramentas de cada era. Este guia cobre desde o veterano PHP 5 até o moderno PHP 8, com técnicas testadas em produção real.

Sumário

O Desafio das Múltiplas Versões

Vamos ser honestos: você provavelmente mantém sistemas em PHP 5.6 (aquele legado que “funciona, não mexe”), migrou alguns para PHP 7.4, e está experimentando o PHP 8. Cada versão tem suas peculiaridades, e debugar requer estratégias diferentes.

1. Diagnóstico Inicial Por Versão

Comandos Essenciais Para Cada PHP

# Descobrindo com qual versão você está lidando
php -v

# PHP 5.x - O veterano
php5 -m | grep -E 'xdebug|opcache|apc'
php5 -d display_errors=1 script.php

# PHP 7.x - O equilibrado
php7.4 -i | grep -E 'error|memory|time'
php7.4 -d opcache.enable=0 script.php

# PHP 8.x - O moderno
php8.2 -i | grep -i jit
php8.2 -d zend.assertions=1 script.php

Tabela de Recursos de Debug por Versão

FeaturePHP 5.6PHP 7.0-7.4PHP 8.0+
error_get_last()
Throwable
get_debug_type()
str_contains()
Typed Properties⚠️ (7.4+)
Match Expression
JIT Debugging

2. Estratégias de Debug Por Versão

PHP 5 – Modo Sobrevivência

// PHP 5.6 - Debug old school
class LegacyDebugger {
    public static function trace($var, $label = '') {
        $backtrace = debug_backtrace();
        $file = basename($backtrace[0]['file']);
        $line = $backtrace[0]['line'];

        error_log(sprintf(
            "[%s] %s:%d - %s: %s",
            date('Y-m-d H:i:s'),
            $file,
            $line,
            $label,
            print_r($var, true)
        ));
    }

    // Porque PHP 5 não tem finally em algumas versões
    public static function safeExecute($callback) {
        $error = null;
        try {
            return call_user_func($callback);
        } catch (Exception $e) {
            $error = $e;
        }

        // Cleanup code aqui
        if ($error) {
            throw $error;
        }
    }
}

// Tratamento de erro fatal no PHP 5
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && ($error['type'] === E_ERROR || $error['type'] === E_PARSE)) {
        error_log("FATAL: " . json_encode($error));
        // Enviar alerta
    }
});

PHP 7 – Poder e Flexibilidade

// PHP 7.x - Recursos modernos
class ModernDebugger {
    // Uso de Throwable (PHP 7+)
    public static function safeCatch(callable $callback) {
        try {
            return $callback();
        } catch (\Throwable $e) {
            self::logException($e);

            // PHP 7.4+ tem getTrace() melhorado
            if (PHP_VERSION_ID >= 70400) {
                $trace = $e->getTraceAsString();
            } else {
                $trace = self::formatTrace($e->getTrace());
            }

            error_log("Stack: " . $trace);
            throw $e;
        }
    }

    // Type hints disponíveis
    public static function validateData(?array $data): bool {
        // Null coalescing operator (PHP 7+)
        $required = $data['required'] ?? false;

        // Spaceship operator para comparação
        $priority = $data['priority'] ?? 0;
        return $priority <=> 100;
    }

    // Group use declarations (PHP 7+)
    public static function checkMemory(): void {
        $usage = memory_get_usage(true);
        $peak = memory_get_peak_usage(true);

        // PHP 7+ tem opcache melhorado
        if (function_exists('opcache_get_status')) {
            $opcache = opcache_get_status();
            error_log("OPcache hits: " . ($opcache['opcache_statistics']['hits'] ?? 0));
        }
    }
}

PHP 8 – Arsenal Completo

// PHP 8.x - Recursos avançados
class AdvancedDebugger {
    // Union types (PHP 8+)
    public static function debug(mixed $data, string|int $level = 'info'): void {
        // Match expression (PHP 8+)
        $prefix = match($level) {
            'error', 1 => '🔴 ERROR',
            'warning', 2 => '🟠 WARNING',
            'info', 3 => '🔵 INFO',
            default => '⚪ DEBUG'
        };

        // get_debug_type() para tipo preciso (PHP 8+)
        $type = get_debug_type($data);

        // Named arguments (PHP 8+)
        self::writeLog(
            message: "$prefix [$type]: " . print_r($data, true),
            timestamp: time(),
            backtrace: debug_backtrace(limit: 3)
        );
    }

    // Attributes para metadados (PHP 8+)
    #[Deprecated("Use debug() instead")]
    public static function oldDebug($data): void {
        self::debug($data);
    }

    // Constructor property promotion (PHP 8+)
    public function __construct(
        private string $logPath = '/tmp/debug.log',
        private bool $verbose = false
    ) {}

    // Nullsafe operator (PHP 8+)
    public static function safeAccess(?object $obj): void {
        // Não precisa mais de isset()
        $value = $obj?->property?->subProperty;

        // String functions novas
        if (str_contains($value ?? '', 'error')) {
            if (str_starts_with($value, 'ERROR:')) {
                // JIT compile info
                if (opcache_get_status()['jit']['enabled'] ?? false) {
                    error_log("JIT enabled - checking optimization");
                }
            }
        }
    }
}

3. Problemas Específicos Por Versão

PHP 5 – Os Clássicos

// Magic quotes (removido no PHP 5.4+)
if (get_magic_quotes_gpc()) {
    $_POST = array_map('stripslashes', $_POST);
}

// mysql_* functions (deprecated)
if (!function_exists('mysqli_connect')) {
    // Fallback para mysql antigo
    $conn = mysql_connect($host, $user, $pass);
    mysql_select_db($db);
} else {
    $conn = mysqli_connect($host, $user, $pass, $db);
}

// Erros de referência
$arr = array();
// PHP 5: Notice apenas
// PHP 7+: Warning
$value = &$arr['nonexistent']['key'];

PHP 7 – Mudanças Breaking

// Division by zero behavior mudou
try {
    // PHP 5: Warning e retorna false
    // PHP 7: DivisionByZeroError
    $result = 10 / 0;
} catch (\DivisionByZeroError $e) {
    error_log("Division by zero caught");
}

// Type declarations mais rígidas
declare(strict_types=1); // PHP 7+

function calculate(int $a, int $b): int {
    return $a + $b;
}

// PHP 7.0: TypeError se passar string
// calculate("10", "20"); // Fatal error

// Uniform variable syntax
// PHP 5 vs PHP 7 interpretação diferente
$foo = 'bar';
$bar = ['baz' => 'value'];
// PHP 5: ${$foo['baz']}
// PHP 7: ($$foo)['baz']

PHP 8 – Novos Comportamentos

// Mudanças em comparação
// PHP 7: 0 == "string" é true
// PHP 8: 0 == "string" é false

// Consistent type errors
try {
    // PHP 8 lança TypeError consistentemente
    strlen([]); // TypeError: strlen(): Argument #1 must be of type string
} catch (\TypeError $e) {
    error_log("Type error: " . $e->getMessage());
}

// Named parameters mudaram dynamic calls
$params = ['param2' => 'value2', 'param1' => 'value1'];
// PHP 8: ordem não importa com named parameters
call_user_func_array('myFunction', $params);

// Warnings promovidos a Errors
try {
    // PHP 7: Warning
    // PHP 8: Error
    $undefined['key'];
} catch (\Error $e) {
    error_log("Undefined variable access");
}

4. Ferramentas de Debug Por Versão

Configuração XDebug Otimizada

; PHP 5 - XDebug 2.x
xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.remote_host=localhost
xdebug.profiler_enable_trigger=1
xdebug.trace_enable_trigger=1

; PHP 7 - XDebug 2.x/3.x
xdebug.mode=debug,profile,trace ; XDebug 3
xdebug.client_host=localhost     ; XDebug 3
xdebug.start_with_request=trigger ; XDebug 3
xdebug.output_dir=/tmp/xdebug

; PHP 8 - XDebug 3.x
xdebug.mode=develop,debug,profile
xdebug.start_with_request=yes
xdebug.discover_client_host=true
xdebug.log_level=0

Profiling Por Versão

class VersionAwareProfiler {
    public static function profile(callable $callback, string $label = 'Operation') {
        $phpVersion = PHP_MAJOR_VERSION;

        // Início
        $startTime = microtime(true);
        $startMemory = memory_get_usage(true);

        // Execução com profiling específico
        if ($phpVersion >= 8) {
            // PHP 8: JIT stats
            $jitBefore = opcache_get_status()['jit'] ?? [];
        }

        $result = $callback();

        // Fim
        $endTime = microtime(true);
        $endMemory = memory_get_usage(true);

        // Relatório
        $report = [
            'php_version' => PHP_VERSION,
            'label' => $label,
            'time_ms' => round(($endTime - $startTime) * 1000, 2),
            'memory_mb' => round(($endMemory - $startMemory) / 1024 / 1024, 2),
            'peak_memory_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2)
        ];

        if ($phpVersion >= 8) {
            $jitAfter = opcache_get_status()['jit'] ?? [];
            $report['jit_buffer_free'] = $jitAfter['buffer_free'] ?? 'N/A';
        }

        error_log("PROFILE: " . json_encode($report));
        return $result;
    }
}

5. Migração Segura Entre Versões

Checklist de Compatibilidade

class CompatibilityChecker {
    public static function checkEnvironment(): array {
        $report = [
            'current_version' => PHP_VERSION,
            'version_id' => PHP_VERSION_ID,
            'checks' => []
        ];

        // PHP 5 para 7
        if (PHP_MAJOR_VERSION == 5) {
            $report['checks']['mysql_extension'] = extension_loaded('mysql') ? '⚠️ Deprecated' : '✅';
            $report['checks']['ereg_functions'] = function_exists('ereg') ? '⚠️ Removed in PHP 7' : '✅';
            $report['checks']['asp_tags'] = ini_get('asp_tags') ? '⚠️ Removed in PHP 7' : '✅';
        }

        // PHP 7 para 8
        if (PHP_MAJOR_VERSION == 7) {
            $report['checks']['libxml_disable_entity_loader'] = 
                function_exists('libxml_disable_entity_loader') ? '⚠️ Deprecated in PHP 8' : '✅';
            $report['checks']['each_function'] = 
                function_exists('each') ? '⚠️ Removed in PHP 8' : '✅';
            $report['checks']['create_function'] = 
                function_exists('create_function') ? '⚠️ Removed in PHP 8' : '✅';
        }

        // Recursos disponíveis
        $report['features'] = [
            'opcache' => extension_loaded('opcache'),
            'apcu' => extension_loaded('apcu'),
            'xdebug' => extension_loaded('xdebug'),
            'jit' => PHP_MAJOR_VERSION >= 8 && opcache_get_status()['jit']['enabled'] ?? false
        ];

        return $report;
    }
}

6.Scripts de Emergência Multi-Versão

🚨 Kit de Sobrevivência Universal

/**
 * emergency-debug.php
 * Funciona em PHP 5.6+
 */

// Detecção de versão e configuração
$phpVersion = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
$isLegacy = PHP_MAJOR_VERSION < 7;
$isModern = PHP_MAJOR_VERSION >= 8;

// Configuração segura para qualquer versão
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', '/tmp/emergency-' . date('Y-m-d') . '.log');

// Handler universal de erros
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($phpVersion) {
    $levels = [
        E_ERROR => 'ERROR',
        E_WARNING => 'WARNING',
        E_NOTICE => 'NOTICE',
        E_DEPRECATED => 'DEPRECATED'
    ];

    $level = $levels[$errno] ?? 'UNKNOWN';
    $message = sprintf(
        "[PHP %s] %s: %s in %s:%d",
        $phpVersion,
        $level,
        $errstr,
        basename($errfile),
        $errline
    );

    error_log($message);

    // Em desenvolvimento, mostra na tela
    if (ini_get('display_errors')) {
        echo "<pre>$message</pre>\n";
    }

    return true; // Previne handler padrão
});

// Exception handler compatível
set_exception_handler(function($e) use ($isLegacy, $isModern) {
    $class = get_class($e);
    $message = $e->getMessage();
    $file = $e->getFile();
    $line = $e->getLine();

    $output = "Uncaught $class: $message\n";
    $output .= "File: $file:$line\n";

    if ($isModern) {
        // PHP 8 tem mais informações
        $output .= "Type: " . get_debug_type($e) . "\n";
    }

    $output .= "Stack trace:\n" . $e->getTraceAsString();

    error_log($output);

    // Resposta HTTP apropriada
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }

    echo "<h1>500 - Internal Server Error</h1>";
    if (ini_get('display_errors')) {
        echo "<pre>$output</pre>";
    }
});

// Shutdown function para pegar erros fatais
register_shutdown_function(function() use ($phpVersion) {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        $message = sprintf(
            "[PHP %s] FATAL: %s in %s:%d",
            $phpVersion,
            $error['message'],
            $error['file'],
            $error['line']
        );

        error_log($message);

        // Tentar enviar alerta (adapte para seu sistema)
        if (function_exists('mail')) {
            @mail(
                'dev-team@company.com',
                'FATAL ERROR - PHP ' . $phpVersion,
                $message
            );
        }
    }
});

// Informações do ambiente
echo "<h2>Debug Information - PHP $phpVersion</h2>";
echo "<pre>";
echo "Memory Usage: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB\n";
echo "Peak Memory: " . round(memory_get_peak_usage(true) / 1024 / 1024, 2) . " MB\n";
echo "Included Files: " . count(get_included_files()) . "\n";

if (PHP_MAJOR_VERSION >= 7) {
    echo "OPcache: " . (function_exists('opcache_get_status') ? 'Enabled' : 'Disabled') . "\n";
}

if (PHP_MAJOR_VERSION >= 8) {
    $jit = opcache_get_status()['jit'] ?? [];
    echo "JIT: " . ($jit['enabled'] ?? false ? 'Enabled' : 'Disabled') . "\n";
}

echo "</pre>";

Tabela de Decisão Rápida

SintomaPHP 5PHP 7PHP 8
White screendisplay_errors=1Check ThrowableCheck TypeError
Memory exhaustedIncrease limitCheck generatorsCheck JIT buffer
Slow performanceAPC cacheOPcacheJIT + Preloading
Syntax errorCheck [] arraysCheck ?? operatorCheck match expression
Type errorsAdd checksUse declare(strict)Use union types
DeprecationSuppress noticesPlan migrationUpdate urgently

Checklist Universal de Debug

□ Identificar versão exata do PHP
□ Verificar logs específicos da versão
□ Testar com error reporting máximo
□ Verificar extensões carregadas
□ Confirmar configurações do php.ini
□ Validar compatibilidade de sintaxe
□ Checar diferenças de comportamento
□ Revisar funções deprecated/removed
□ Testar handlers de erro/exception
□ Documentar solução por versão

Conclusão: Dominando Todas as Eras do PHP

Trabalhar com múltiplas versões de PHP é como ser fluente em diferentes dialetos do mesmo idioma. Cada versão tem suas forças:

  • PHP 5: Estável, previsível, amplamente suportado
  • PHP 7: Rápido, moderno, melhor handling de erros
  • PHP 8: Poderoso, JIT, recursos de linguagem avançados

O segredo é conhecer as peculiaridades de cada versão e ter um toolkit que funcione em todas elas. Com este guia, você está preparado para debugar qualquer versão que aparecer no seu caminho.

Lembre-se: O melhor código é aquele que funciona em produção, independente da versão do PHP. 🚀


Sobre o autor: Mauro Rocha Tavares – Debugando PHP desde a versão 4, sou um sobrevivente das magic quotes, também já usei muito var_dump() e print_r(), veterano das migrações impossíveis.

Compartilhe suas experiências: Qual foi o bug mais desafiador que você encontrou em diferentes versões do PHP?


Tags: #PHP5 #PHP7 #PHP8 #Debugging #LegacyCode #ModernPHP #Troubleshooting #WebDevelopment #DevOps #BackendDevelopment #Backend

Compartilhe este artigo

💬 Comentários

Ainda não há comentários. Seja o primeiro a comentar!

Deixe um comentário