CtrlK
BlogDocsLog inGet started
Tessl Logo

giuseppe-trisciuoglio/developer-kit

Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.

90

Quality

90%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Risky

Do not use without reviewing

This version of the tile failed moderation
Moderation pipeline encountered an internal error
Overview
Quality
Evals
Security
Files

error-handling.mdplugins/developer-kit-php/rules/

paths:
**/*.php

Rule: PHP Error Handling

Context

Establish a consistent error handling strategy for PHP applications, ensuring meaningful error reporting, proper exception hierarchies, and clean recovery patterns.

Guidelines

Exception Hierarchy

  • Create a base BusinessException extending \RuntimeException for all domain-specific errors
  • Create specific exceptions for each error domain (e.g., OrderNotFoundException, PaymentDeclinedException)
  • Include meaningful error messages with relevant context (IDs, parameters)
  • Use exception codes for machine-readable error identification
abstract class BusinessException extends \RuntimeException
{
    public function __construct(string $message, int $code = 0, ?\Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }
}

final class OrderNotFoundException extends BusinessException
{
    public function __construct(int $orderId)
    {
        parent::__construct(
            message: sprintf('Order with ID %d was not found', $orderId),
            code: 404,
        );
    }
}

Global Exception Handling

  • Use framework-specific exception handlers (Laravel: Handler, Symfony: EventListener)
  • Return standardized JSON error responses for API endpoints
  • Map exceptions to appropriate HTTP status codes:
    • 404 Not Found — resource not found
    • 400 Bad Request — validation errors
    • 409 Conflict — business rule violations
    • 422 Unprocessable Entity — semantically invalid input
    • 500 Internal Server Error — unexpected errors only

Error Response Format

{
  "type": "order_not_found",
  "title": "Order Not Found",
  "status": 404,
  "detail": "Order with ID 12345 was not found"
}

Best Practices

  • Never use @ error suppression operator
  • Never catch \Exception or \Throwable in business logic — only at error boundaries
  • Never silently swallow exceptions (empty catch blocks)
  • Always preserve the previous exception: throw new AppException('msg', 0, $previous)
  • Use PHP 8.0+ throw expression in arrow functions and null coalescing
  • Log exceptions with full context using PSR-3 LoggerInterface
  • Use finally for cleanup code that must always execute
  • Validate input at the boundary (controller/command) using framework validation

Validation

  • Use framework validation (Laravel Requests, Symfony Constraints) at the API boundary
  • Do not throw exceptions for validation — let the framework handle validation errors
  • Throw domain exceptions only for business rule violations in the service layer

Examples

✅ Good

<?php

declare(strict_types=1);

final class OrderService
{
    public function __construct(
        private readonly OrderRepositoryInterface $repository,
        private readonly LoggerInterface $logger,
    ) {}

    public function findById(int $orderId): Order
    {
        return $this->repository->find($orderId)
            ?? throw new OrderNotFoundException($orderId);
    }

    public function process(int $orderId): OrderResult
    {
        try {
            $order = $this->findById($orderId);
            $result = $this->paymentGateway->charge($order);
        } catch (PaymentGatewayException $e) {
            $this->logger->error('Payment failed for order {orderId}', [
                'orderId' => $orderId,
                'exception' => $e,
            ]);
            throw new PaymentProcessingException($orderId, previous: $e);
        }

        $this->logger->info('Order {orderId} processed', ['orderId' => $orderId]);

        return $result;
    }
}

❌ Bad

<?php

class OrderService
{
    public function process($id)
    {
        try {
            $order = $this->repo->find($id);
            $this->pay($order);
        } catch (\Exception $e) {
            // Silent swallow — bug hidden forever
        }
    }

    public function findById($id)
    {
        $order = @$this->repo->find($id);  // Error suppression
        if (!$order) {
            return null;  // Returning null instead of throwing
        }
        return $order;
    }
}

plugins

CHANGELOG.md

context7.json

CONTRIBUTING.md

README_CN.md

README_ES.md

README_IT.md

README.md

tessl.json

tile.json