home / skills / victorsmaniotto / degestao / legacy-modernizer

legacy-modernizer skill

/.agent/skills/legacy-modernizer

npx playbooks add skill victorsmaniotto/degestao --skill legacy-modernizer

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.7 KB
---
name: legacy-modernizer
description: Modernização de código PHP legado para padrões atuais (PHP 7.4-8.3). Usar para converter código procedural para OOP, atualizar sintaxe deprecated, implementar type hints, substituir arrays por objetos/collections, modernizar callbacks para closures/arrow functions, converter globals para dependency injection, e preparar código para migração de frameworks.
---

# Legacy Modernizer

Skill para transformação de código PHP legado em código moderno e maintainable.

## Checklist de Modernização

1. **Sintaxe PHP 8.x** - Type hints, named arguments, match, enums
2. **OOP** - Classes, interfaces, traits, composition
3. **SOLID** - Single responsibility, dependency injection
4. **PSR** - Autoload, coding style, interfaces
5. **Error Handling** - Exceptions em vez de error codes
6. **Testing** - Código testável e desacoplado

## Transformações Comuns

### 1. Sintaxe Moderna

```php
// ❌ ANTES: PHP 5.x
function getUser($id) {
    global $db;
    $result = mysql_query("SELECT * FROM users WHERE id = " . $id);
    if ($result) {
        return mysql_fetch_assoc($result);
    }
    return false;
}

// ✅ DEPOIS: PHP 8.x
function getUser(int $id): ?array
{
    return DB::table('users')->find($id)?->toArray();
}
```

### 2. Type Declarations

```php
// ❌ ANTES
function calcularTotal($items, $desconto) {
    $total = 0;
    foreach ($items as $item) {
        $total += $item['valor'];
    }
    return $total - $desconto;
}

// ✅ DEPOIS
function calcularTotal(array $items, float $desconto = 0): float
{
    $total = array_sum(array_column($items, 'valor'));
    return max(0, $total - $desconto);
}

// ✅ MELHOR: Com objetos
function calcularTotal(Collection $items, float $desconto = 0): float
{
    return max(0, $items->sum('valor') - $desconto);
}
```

### 3. Procedural para OOP

```php
// ❌ ANTES: Funções soltas
function criar_contrato($dados) { ... }
function atualizar_contrato($id, $dados) { ... }
function buscar_contrato($id) { ... }
function listar_contratos($filtros) { ... }

// ✅ DEPOIS: Service Class
class ContractService
{
    public function __construct(
        private ContractRepository $repository,
        private EventDispatcher $events
    ) {}

    public function create(array $data): Contract
    {
        $contract = $this->repository->create($data);
        $this->events->dispatch(new ContractCreated($contract));
        return $contract;
    }

    public function update(int $id, array $data): Contract
    {
        $contract = $this->repository->findOrFail($id);
        $contract->update($data);
        return $contract;
    }

    public function find(int $id): ?Contract
    {
        return $this->repository->find($id);
    }

    public function list(array $filters = []): Collection
    {
        return $this->repository->filter($filters);
    }
}
```

### 4. Global State para DI

```php
// ❌ ANTES: Globals
function enviarEmail($para, $assunto, $corpo) {
    global $config;
    $mail = new PHPMailer();
    $mail->Host = $config['smtp_host'];
    // ...
}

// ✅ DEPOIS: Dependency Injection
class EmailService
{
    public function __construct(
        private readonly MailerInterface $mailer,
        private readonly MailConfig $config
    ) {}

    public function send(string $to, string $subject, string $body): void
    {
        $this->mailer
            ->to($to)
            ->subject($subject)
            ->body($body)
            ->send();
    }
}
```

### 5. Arrays para Value Objects

```php
// ❌ ANTES: Array associativo
$contrato = [
    'cliente' => 'João',
    'valor' => 1500.00,
    'data' => '2024-01-15',
    'status' => 'ativo'
];

// ✅ DEPOIS: DTO/Value Object
readonly class Contract
{
    public function __construct(
        public string $cliente,
        public float $valor,
        public DateTimeImmutable $data,
        public ContractStatus $status
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            cliente: $data['cliente'],
            valor: (float) $data['valor'],
            data: new DateTimeImmutable($data['data']),
            status: ContractStatus::from($data['status'])
        );
    }
}

enum ContractStatus: string
{
    case Ativo = 'ativo';
    case Cancelado = 'cancelado';
    case Finalizado = 'finalizado';

    public function label(): string
    {
        return match($this) {
            self::Ativo => 'Ativo',
            self::Cancelado => 'Cancelado',
            self::Finalizado => 'Finalizado',
        };
    }
}
```

### 6. Callbacks para Arrow Functions

```php
// ❌ ANTES: Callback verbose
$ativos = array_filter($contratos, function($c) {
    return $c['status'] == 'ativo';
});

$valores = array_map(function($c) {
    return $c['valor'];
}, $ativos);

$total = array_reduce($valores, function($carry, $v) {
    return $carry + $v;
}, 0);

// ✅ DEPOIS: Arrow functions + Collection
$total = collect($contratos)
    ->filter(fn($c) => $c['status'] === 'ativo')
    ->sum('valor');
```

### 7. Switch para Match

```php
// ❌ ANTES
switch ($status) {
    case 'pending':
        $label = 'Pendente';
        $color = 'yellow';
        break;
    case 'active':
        $label = 'Ativo';
        $color = 'green';
        break;
    case 'cancelled':
        $label = 'Cancelado';
        $color = 'red';
        break;
    default:
        $label = 'Desconhecido';
        $color = 'gray';
}

// ✅ DEPOIS
[$label, $color] = match($status) {
    'pending' => ['Pendente', 'yellow'],
    'active' => ['Ativo', 'green'],
    'cancelled' => ['Cancelado', 'red'],
    default => ['Desconhecido', 'gray'],
};
```

### 8. Error Handling

```php
// ❌ ANTES: Error codes
function processarPagamento($dados) {
    if (!isset($dados['valor'])) {
        return ['erro' => true, 'mensagem' => 'Valor obrigatório'];
    }
    if ($dados['valor'] <= 0) {
        return ['erro' => true, 'mensagem' => 'Valor inválido'];
    }
    // processar...
    return ['erro' => false, 'id' => 123];
}

// ✅ DEPOIS: Exceptions
class PaymentService
{
    public function process(PaymentData $data): Payment
    {
        $this->validate($data);
        
        try {
            return $this->gateway->charge($data);
        } catch (GatewayException $e) {
            throw new PaymentFailedException(
                "Falha no pagamento: {$e->getMessage()}",
                previous: $e
            );
        }
    }

    private function validate(PaymentData $data): void
    {
        if ($data->valor <= 0) {
            throw new InvalidArgumentException('Valor deve ser positivo');
        }
    }
}
```

## Padrão de Migração Incremental

```
1. Criar interfaces para código existente
2. Implementar nova versão atrás da interface
3. Usar feature flags para alternar
4. Remover código antigo após validação
```

```php
// Interface de abstração
interface ContractRepositoryInterface
{
    public function find(int $id): ?Contract;
    public function save(Contract $contract): void;
}

// Implementação legada (wrapper)
class LegacyContractRepository implements ContractRepositoryInterface
{
    public function find(int $id): ?Contract
    {
        $data = buscar_contrato($id); // função legada
        return $data ? Contract::fromArray($data) : null;
    }
}

// Nova implementação
class EloquentContractRepository implements ContractRepositoryInterface
{
    public function find(int $id): ?Contract
    {
        return ContractModel::find($id)?->toDomain();
    }
}

// Service Provider com feature flag
$this->app->bind(
    ContractRepositoryInterface::class,
    config('features.new_repository') 
        ? EloquentContractRepository::class 
        : LegacyContractRepository::class
);
```

## Scripts Úteis

- `scripts/analyze-legacy.php` - Análise de código legado
- `scripts/convert-array-to-dto.php` - Converter arrays em DTOs