Skip to content

Latest commit

 

History

History
542 lines (389 loc) · 14 KB

File metadata and controls

542 lines (389 loc) · 14 KB

PivotPHP ReactPHP Troubleshooting Guide

Common Issues and Solutions

Based on real development experience and issues encountered during implementation.

Nota: as três seções abaixo ("PSR-7 Compatibility Issues", "Header Access Issues", "Express.js Pattern Issues") descreviam uma arquitetura anterior à introdução de suporte PSR-7 nativo neste pacote (CHANGELOG.md, v0.0.2: "Removed obsolete Psr7CompatibilityAdapter"). O exemplo real e funcional deste pacote (examples/server.php) usa ServerRequestInterface/ResponseInterface PSR-7 diretamente, com handlers que retornam ResponseInterface — não o padrão function($req, $res): void descrito abaixo. Corrigido o que dava para verificar contra examples/server.php; o restante foi atualizado com uma nota de cautela em vez de reescrito linha a linha.


PSR-7 Compatibility Issues

Este workaround está obsoleto

O script switch-psr7-version.php e o erro de incompatibilidade de getProtocolVersion() descrito abaixo eram um problema real quando pivotphp/core só suportava PSR-7 v1.x ou v2.x, exigindo a troca manual. Desde então, pivotphp/core passou a suportar as duas versões simultaneamente sem precisar do script (ver pivotphp-core, changelog da versão que corrigiu a compatibilidade real com psr/http-message 2.0). Se você ainda encontrar esse erro, confira primeiro se está usando uma versão desatualizada de pivotphp/core antes de recorrer ao script abaixo.

Conteúdo original (pode estar obsoleto)

Error: "Declaration of React\Http\Io\AbstractMessage::getProtocolVersion() must be compatible with..."

Symptoms:

Fatal error: Declaration of React\Http\Io\AbstractMessage::getProtocolVersion() 
must be compatible with Psr\Http\Message\MessageInterface::getProtocolVersion(): string

Cause: PivotPHP Core is using PSR-7 v2.x while ReactPHP requires PSR-7 v1.x.

Solution:

# Switch PivotPHP Core to PSR-7 v1.x
php vendor/pivotphp/core/scripts/switch-psr7-version.php 1
composer update psr/http-message

# Verify the change
php vendor/pivotphp/core/scripts/switch-psr7-version.php --check

Prevention: Always use PSR-7 v1.x when integrating with ReactPHP.


Request/Response Handling Issues

RequestBridge::convertFromReact() retorna PSR-7 ServerRequestInterface

Assinatura real (src/Bridge/RequestBridge.php:29): convertFromReact(ServerRequestInterface $reactRequest): ServerRequestInterface. Não converte para a classe híbrida PivotPHP\Core\Http\Request — o erro descrito originalmente nesta seção partia da premissa contrária. Se você receber um erro de tipo aqui, confira se está passando ServerRequestInterface corretamente pela cadeia de handlers, não tentando forçar conversão para \PivotPHP\Core\Http\Request.


Header Access Issues

Use a API PSR-7 padrão, não ->header('camelCase')

examples/server.php (o exemplo real e funcional deste pacote) acessa headers via $request->getHeaders() PSR-7 puro. Não confirmamos, dentro deste repositório, que ->header('camelCase') seja a API real de acesso a headers — se você encontrar esse método, prefira a forma PSR-7 abaixo, que sabemos que funciona:

// ✅ PSR-7 padrão — confirmado em examples/server.php
$contentType = $request->getHeaderLine('Content-Type');
$auth = $request->getHeaderLine('Authorization');
$allHeaders = $request->getHeaders();
Conteúdo original (não verificado nesta correção — pode estar obsoleto)

Error: Headers Return Null

Symptoms:

$contentType = $request->header('Content-Type'); // Returns null

Cause: PivotPHP converts header names to camelCase during Request construction.

Solution: Use camelCase header names (contentType, authorization, xApiKey, etc.)


Express.js Pattern Issues

Route handlers retornam ResponseInterface — não são void

examples/server.php mostra o padrão real: handlers de rota recebem ServerRequestInterface (e array $args para parâmetros de rota) e retornam ResponseInterface, sem um segundo parâmetro de response:

// ✅ Confirmado em examples/server.php
$router->get('/hello/{name}', function (ServerRequestInterface $request, array $args): ResponseInterface {
    return Response::json(['message' => "Hello, {$args['name']}!"]);
});

Middleware ($app->use(...)), por sua vez, usa um padrão de 3 argumentos que retorna a resposta (não é void):

// ✅ Confirmado em examples/server.php
$app->use(function (ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface {
    $response = $next($request, $response);
    return $response->withHeader('X-Server', 'PivotPHP/ReactPHP');
});
Conteúdo original (contradiz o exemplo real acima — mantido só como histórico)

Versões anteriores desta página descreviam um padrão function($req, $res): void para rotas, com a resposta sendo enviada via $response->json($data) em vez de retornada. Isso não bate com examples/server.php — trate como obsoleto.


Service Provider and Container Issues

Error: "Too few arguments to function Application::get()"

Symptoms:

ArgumentCountError: Too few arguments to function PivotPHP\Core\Core\Application::get(), 
1 passed and exactly 2 expected

Cause: Using wrong method to access services from container.

Solution: Use make() instead of get():

// ❌ Wrong
$router = $app->get('router');

// ✅ Correct
$router = $app->make('router');

// ✅ With existence check
if ($app->has('router')) {
    $router = $app->make('router');
}

Prevention: Use PSR-11 container methods: has(), make().


Error: Services Not Available

Symptoms: Services registered but not accessible, "Service not found" errors.

Cause: Accessing services before calling boot().

Solution: Always boot before accessing services:

// ✅ Correct order
$app->register(new AppServiceProvider());
$app->register(new RouteServiceProvider());
$app->boot(); // Boot first!

// Now services are available
$config = $app->make('config');
$router = $app->make('router');

Prevention: Follow the register → boot → use pattern.


Testing Issues

Error: "Class 'PivotPHP\Core\Http\Factory\Psr17Factory' not found"

Symptoms:

Error: Class "PivotPHP\Core\Http\Factory\Psr17Factory" not found

Cause: Using incorrect factory class names.

Solution: Use correct PivotPHP factory classes:

// ❌ Wrong - this class doesn't exist
use PivotPHP\Core\Http\Factory\Psr17Factory;

// ✅ Correct factory classes
use PivotPHP\Core\Http\Psr7\Factory\RequestFactory;
use PivotPHP\Core\Http\Psr7\Factory\ResponseFactory;
use PivotPHP\Core\Http\Psr7\Factory\ServerRequestFactory;
use PivotPHP\Core\Http\Psr7\Factory\StreamFactory;
use PivotPHP\Core\Http\Psr7\Factory\UriFactory;

Prevention: Check actual class locations in PivotPHP Core.


Error: "Call to undefined method React\EventLoop\Loop::create()"

Symptoms:

Error: Call to undefined method React\EventLoop\Loop::create()

Cause: Using non-existent ReactPHP Loop method.

Solution: Use existing loop instance:

// ❌ Wrong - create() doesn't exist
protected function tearDown(): void
{
    $this->loop->stop();
    Loop::set(Loop::create()); // This fails
}

// ✅ Correct - just stop the loop
protected function tearDown(): void
{
    $this->loop->stop();
    parent::tearDown();
}

Prevention: Use ReactPHP documentation for correct Loop API.


Request Data Access Issues

Error: "Call to undefined method HeaderRequest::set()"

Symptoms:

Error: Call to undefined method PivotPHP\Core\Http\HeaderRequest::set()

Cause: Trying to modify immutable Request objects.

Solution: PivotPHP Request is immutable by design. Use global variables:

// ❌ Wrong - trying to modify after creation
$pivotRequest->headers->set('content-type', 'application/json');
$pivotRequest->query->page = 2;

// ✅ Correct - set globals before creation
$_SERVER['HTTP_CONTENT_TYPE'] = 'application/json';
$_GET['page'] = '2';
$_POST['data'] = 'value';

$pivotRequest = new Request('POST', '/users', '/users');

Prevention: Understand PivotPHP's immutable design pattern.


ReactPHP Server Issues

Error: "Address already in use (EADDRINUSE)"

Symptoms:

RuntimeException: Failed to listen on "tcp://127.0.0.1:8080": Address already in use (EADDRINUSE)

Cause: Port is already in use by another process.

Solutions:

# Find process using the port
lsof -i :8080
netstat -tulpn | grep :8080

# Kill the process
kill -9 <PID>

# Or use a different port
$server->listen('0.0.0.0:8081');

Prevention: Use different ports for different environments.


Error: "Typed property ReactServer::$socketServer must not be accessed before initialization"

Symptoms:

Error: Typed property PivotPHP\ReactPHP\Server\ReactServer::$socketServer 
must not be accessed before initialization

Cause: Accessing ReactServer properties before calling listen().

Solution: Call methods in correct order:

$server = new ReactServer($app, $loop);
$server->listen('0.0.0.0:8080'); // Initialize first
$server->getLoop(); // Now safe to access properties

Prevention: Always call listen() before accessing server properties.


Memory and Performance Issues

Issue: Memory Leaks in Long-Running Processes

Symptoms: Memory usage grows continuously over time.

Debugging:

// Add memory monitoring
$app->get('/memory', function ($request, $response) {
    $response->json([
        'memory_usage' => memory_get_usage(true),
        'memory_peak' => memory_get_peak_usage(true),
        'memory_limit' => ini_get('memory_limit')
    ]);
});

Solutions:

  1. Avoid static arrays that grow over time
  2. Clean up resources explicitly
  3. Use object pooling for frequently created objects
  4. Monitor memory regularly
// ❌ Wrong - static array grows forever
class MyController {
    private static $cache = [];
    
    public function index($request, $response) {
        self::$cache[] = $someData; // Memory leak!
    }
}

// ✅ Correct - limit cache size
class MyController {
    private static $cache = [];
    private const MAX_CACHE_SIZE = 1000;
    
    public function index($request, $response) {
        if (count(self::$cache) >= self::MAX_CACHE_SIZE) {
            array_shift(self::$cache); // Remove oldest
        }
        self::$cache[] = $someData;
    }
}

Prevention: Design for long-running processes from the start.


Database Connection Issues

Issue: Database Connections Timing Out

Symptoms: "MySQL server has gone away" errors after period of inactivity.

Solution: Implement connection health checks:

$app->singleton('database', function() {
    return new DatabaseConnection();
});

$app->get('/api/users', function ($request, $response) use ($app) {
    try {
        $db = $app->make('database');
        
        // Health check before query
        if (!$db->ping()) {
            $db->reconnect();
        }
        
        $users = $db->query('SELECT * FROM users');
        $response->json($users);
        
    } catch (PDOException $e) {
        $response->status(503)->json(['error' => 'Database unavailable']);
    }
});

Prevention: Use connection pooling or implement automatic reconnection.


Development and Debugging

Enable Debug Mode

Set environment variables:

APP_DEBUG=true
APP_ENV=development
REACTPHP_DEBUG=true

Add debug middleware:

if ($_ENV['APP_DEBUG'] ?? false) {
    $app->use(new DebugMiddleware());
}

Logging Configuration

Add comprehensive logging:

use Psr\Log\LoggerInterface;

$server = new ReactServer($app, $loop, $logger);

// Log all requests
$app->use(function ($request, $response, $next) use ($logger) {
    $start = microtime(true);
    
    $next($request, $response);
    
    $duration = microtime(true) - $start;
    $logger->info('Request processed', [
        'method' => $request->getMethod(),
        'path' => $request->getPath(),
        'duration' => $duration,
        'memory' => memory_get_usage(true)
    ]);
});

Quality Assurance

Run All Quality Checks

# PHPStan static analysis
composer phpstan

# PSR-12 code style check
composer cs:check

# Fix code style issues
composer cs:fix

# Run all tests
composer test

# Run all quality checks
composer quality:check

Continuous Integration

Example GitHub Actions workflow:

name: CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.1'
          
      - run: composer install
      - run: composer quality:check
      - run: composer test

Getting Help

Debug Information to Collect

When reporting issues, include:

  1. PHP Version: php --version
  2. PivotPHP Version: Check composer.json
  3. ReactPHP Version: Check composer.json
  4. PSR-7 Version: php vendor/pivotphp/core/scripts/switch-psr7-version.php --check
  5. Error Messages: Full stack traces
  6. Configuration: Server settings, environment variables
  7. Test Case: Minimal code to reproduce the issue

Useful Commands

# Check PSR-7 version
php vendor/pivotphp/core/scripts/switch-psr7-version.php --check

# Validate composer dependencies
composer validate

# Show installed packages
composer show

# Check for security vulnerabilities
composer audit

# Run ReactPHP server with debugging
APP_DEBUG=true php server.php

This troubleshooting guide covers the most common issues encountered during ReactPHP integration with PivotPHP Core. Most problems stem from PSR-7 version conflicts, misunderstanding PivotPHP's immutable design, or incorrect usage of the Express.js pattern.