A black-and-white photograph of a technician operating the control console of a mechanical differential analyzer, in front of a dense wall of patch-panel switchboards
AI & LLMs

AI-Enhanced PHP Development: Tools and Workflows

•10 min read•By Joseph Edmonds•Image: NASA, public domain, via Wikimedia Commons

How AI tools like GitHub Copilot and OpenAI's APIs can speed up PHP development, without you handing over your judgement about what good code actually looks like.

AI tools are genuinely useful for PHP development, though it's worth being honest about what that actually means in practice: they amplify the skill you already have rather than replace your judgement, so any productivity gain only really shows up if you're still doing the reviewing yourself.

The tools below fall into two rough categories: pair-programming assistants for boilerplate and test generation, and API-level integrations for code review, refactoring, and error analysis. What matters more than the tools themselves is how you validate what they produce.

The AI Development Toolkit

GitHub Copilot

GitHub Copilot is good at:

  • Boilerplate code generation: Controllers, models, service classes
  • Test case creation: Unit tests, integration tests, mock objects
  • Documentation: PHPDoc comments, README files, inline comments
  • Code completion: Complex function implementations, regex patterns

Example workflow with Copilot:

<?php

declare(strict_types=1);

namespace App\Services\User;

use App\Entities\User;
use App\Exceptions\{ValidationException};
use App\Repositories\UserRepository;
use App\ValueObjects\{EmailAddress, UserId, UserName};

// Type this comment:
// Create a UserService class with methods to create, update, and delete users

// Modern AI-generated code with proper typing:
final readonly class UserService
{
    public function __construct(
        private UserRepository $userRepository,
        private UserValidator $validator,
        private PasswordHasher $passwordHasher,
    ) {
    }

    public function createUser(array $userData): User
    {
        $validationResult = $this->validator->validate($userData);

        if (!$validationResult->isValid()) {
            throw new ValidationException($validationResult->getErrors());
        }

        $user = User::create(
            UserId::generate(),
            EmailAddress::fromString($userData['email']),
            UserName::fromString($userData['name']),
            $this->passwordHasher->hash($userData['password'])
        );

        return $this->userRepository->save($user);
    }

    public function updateUser(UserId $id, array $userData): User
    {
        $user = $this->userRepository->findById($id)
            ?? throw new UserNotFoundException("User not found: {$id->value}");

        if (isset($userData['email'])) {
            $user->changeEmail(EmailAddress::fromString($userData['email']));
        }

        if (isset($userData['name'])) {
            $user->changeName(UserName::fromString($userData['name']));
        }

        return $this->userRepository->save($user);
    }

    public function deleteUser(UserId $id): void
    {
        $user = $this->userRepository->findById($id)
            ?? throw new UserNotFoundException("User not found: {$id->value}");

        $this->userRepository->delete($user);
    }
}

OpenAI APIs

OpenAI APIs can be integrated directly into your PHP applications:

<?php

declare(strict_types=1);

namespace App\AI\CodeReview;

use App\Contracts\AIClientInterface;
use App\Exceptions\{CodeReviewException};
use App\ValueObjects\{AIPrompt, CodeSnippet, ReviewResult};
use Psr\Log\LoggerInterface;

final readonly class AICodeReviewer
{
    public function __construct(
        private AIClientInterface $aiClient,
        private LoggerInterface $logger,
        private string $model = 'gpt-4-turbo',
        private int $maxTokens = 2000,
    ) {
    }

    public function reviewCode(CodeSnippet $code): ReviewResult
    {
        $systemPrompt = AIPrompt::system(<<< 'PROMPT'
            You are a senior PHP 8.3+ developer reviewing code for:
            - Modern PHP syntax and features
            - Type safety and strict typing
            - Security vulnerabilities
            - Performance optimizations
            - SOLID principles adherence
            - Best practices and code quality
            
            Provide specific, actionable feedback with code examples.
            PROMPT);

        $userPrompt = AIPrompt::user(
            "Please review this PHP code:\n\n" . $code->content
        );

        try {
            $response = $this->aiClient->chat([
                'model'       => $this->model,
                'max_tokens'  => $this->maxTokens,
                'temperature' => 0.1, // Low temperature for consistent reviews
                'messages'    => [
                    $systemPrompt->toArray(),
                    $userPrompt->toArray(),
                ],
            ]);

            $reviewContent = $response['choices'][0]['message']['content'];

            $this->logger->info('Code review completed', [
                'code_length' => strlen($code->content),
                'tokens_used' => $response['usage']['total_tokens'],
            ]);

            return $this->parseReviewResponse($reviewContent);
        } catch (Throwable $e) {
            $this->logger->error('AI code review failed', [
                'error'        => $e->getMessage(),
                'code_snippet' => substr($code->content, 0, 100) . '...',
            ]);

            throw new CodeReviewException(
                "Code review failed: {$e->getMessage()}",
                previous: $e
            );
        }
    }

    private function parseReviewResponse(string $response): ReviewResult
    {
        // Parse structured review response
        return ReviewResult::fromAIResponse($response);
    }

    public function batchReviewFiles(array $files): array
    {
        $reviews = [];

        foreach ($files as $file) {
            $code           = CodeSnippet::fromFile($file);
            $reviews[$file] = $this->reviewCode($code);
        }

        return $reviews;
    }
}

Claude

Claude tends to be stronger on:

  • Architecture discussions and design patterns
  • Complex refactoring strategies
  • Performance optimisation analysis
  • Security vulnerability assessment

AI-Enhanced Development Workflows

1. Test-Driven Development with AI

AI can speed up TDD by generating a solid set of test cases:

<?php

declare(strict_types=1);

use PHPUnit\Framework\TestCase;

// Describe your class functionality
// Generate test cases for a UserValidator class that validates email, password strength, and required fields
// AI generates:
final class UserValidatorTest extends TestCase
{
    private UserValidator $validator;

    protected function setUp(): void
    {
        $this->validator = new UserValidator();
    }

    public function testValidEmailIsAccepted(): void
    {
        $result = $this->validator->validateEmail('[email protected]');

        $this->assertTrue($result->isValid());
    }

    public function testInvalidEmailIsRejected(): void
    {
        $result = $this->validator->validateEmail('invalid-email');

        $this->assertFalse($result->isValid());
        $this->assertContains('Invalid email format', $result->getErrors());
    }

    // ... more test cases
}

2. Code Review Automation

Integrate AI into your review process:

#!/bin/bash
# Git hook that runs AI code review
git diff --cached --name-only | grep '\.php
#39; | while read file; do if [ -f "$file" ]; then echo "AI reviewing $file..." php ai-review.php "$file" fi done

3. Documentation Generation

AI can generate a first pass at documentation:

<?php

declare(strict_types=1);

final class OrderService
{
    /**
     * AI-generated PHPDoc example
     *
     * @param array $orderData The order data containing items, customer info, and payment details
     * @throws InvalidOrderException When order data is invalid or incomplete
     * @throws PaymentException When payment processing fails
     * @return OrderResult Contains order ID, status, and transaction details
     */
    public function processOrder(array $orderData): OrderResult
    {
        // Implementation...
    }
}

Best Practices for AI-Enhanced PHP Development

1. Validate AI-Generated Code

Never trust AI-generated code blindly. Always review and test it:

  • Check for security vulnerabilities
  • Ensure error handling is appropriate
  • Verify performance characteristics
  • Confirm adherence to coding standards

2. Use AI for Rapid Prototyping

AI is great for creating initial implementations that you can then refine:

<?php

declare(strict_types=1);

namespace App\Shopping;

use App\Entities\Product;

// AI-generated prototype (basic)
class ShoppingCart
{
    private array $items = [];

    public function addItem(Product $product, int $quantity = 1): void
    {
        $this->items[] = ['product' => $product, 'quantity' => $quantity];
    }

    public function getTotal(): float
    {
        return array_sum(array_map(function (array $item) {
            return $item['product']->getPrice() * $item['quantity'];
        }, $this->items));
    }
}

Once the prototype proves the concept, refine it with value objects, a proper collection, and the domain rules a shopping cart actually needs:

<?php

declare(strict_types=1);

namespace App\Shopping;

use App\Collections\CartItemCollection;
use App\Entities\Product;
use App\Exceptions\{InvalidQuantityException, ProductNotFoundException};
use App\ValueObjects\{Money, ProductId, Quantity};

// Refine with modern PHP patterns and proper domain modelling
final class ShoppingCart
{
    private CartItemCollection $items;

    public function __construct()
    {
        $this->items = new CartItemCollection();
    }

    public function addItem(Product $product, Quantity $quantity): void
    {
        if ($quantity->isZero()) {
            throw new InvalidQuantityException('Quantity must be positive');
        }

        $existingItem = $this->items->findByProductId($product->getId());

        if ($existingItem !== null) {
            $existingItem->increaseQuantity($quantity);
        } else {
            $this->items->add(new CartItem($product, $quantity));
        }
    }

    public function removeItem(ProductId $productId): void
    {
        $item = $this->items->findByProductId($productId)
            ?? throw new ProductNotFoundException("Product not found: {$productId->value}");

        $this->items->remove($item);
    }

    public function getTotal(): Money
    {
        return $this->items->reduce(
            Money::zero(),
            fn (Money $total, CartItem $item) => $total->add($item->getSubtotal())
        );
    }

    public function getItemCount(): int
    {
        return $this->items->count();
    }

    public function isEmpty(): bool
    {
        return $this->items->isEmpty();
    }

    public function clear(): void
    {
        $this->items = new CartItemCollection();
    }
}

3. AI-Assisted Refactoring

You can use AI to spot refactoring opportunities:

<?php

declare(strict_types=1);

// Ask AI: "How can I refactor this method to improve readability and maintainability?"
// Before: Basic validation with mixed concerns
function processUserRegistration(array $data, UserRepository $userRepository)
{
    if (!isset($data['email']) || !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
        throw new Exception('Invalid email');
    }

    if (!isset($data['password']) || strlen($data['password']) < 8) {
        throw new Exception('Password too short');
    }

    return $userRepository->create($data);
}

Asked to refactor for readability and maintainability, AI can propose a proper separation of concerns, with validation, persistence, and event dispatch each becoming their own responsibility:

<?php

declare(strict_types=1);

namespace App\Services\User;

use App\Exceptions\ValidationException;
use App\Repositories\UserRepository;
use App\Validators\UserRegistrationValidator;
use App\ValueObjects\{EmailAddress, Password, UserRegistrationData};

// After: Modern refactored version with proper separation of concerns
final readonly class UserRegistrationService
{
    public function __construct(
        private UserRegistrationValidator $validator,
        private UserRepository $userRepository,
        private PasswordHasher $passwordHasher,
        private EventDispatcher $eventDispatcher,
    ) {
    }

    public function processUserRegistration(array $data): User
    {
        $registrationData = $this->createRegistrationData($data);
        $validationResult = $this->validator->validate($registrationData);

        if (!$validationResult->isValid()) {
            throw new ValidationException($validationResult->getViolations());
        }

        $user = $this->createUser($registrationData);
        $this->userRepository->save($user);

        $this->eventDispatcher->dispatch(
            new UserRegisteredEvent($user->getId(), $user->getEmail())
        );

        return $user;
    }

    private function createRegistrationData(array $data): UserRegistrationData
    {
        return new UserRegistrationData(
            email: EmailAddress::fromString($data['email'] ?? ''),
            password: Password::fromString($data['password'] ?? ''),
            name: UserName::fromString($data['name'] ?? '')
        );
    }

    private function createUser(UserRegistrationData $data): User
    {
        return User::register(
            UserId::generate(),
            $data->email,
            $data->name,
            $this->passwordHasher->hash($data->password)
        );
    }
}

Implementing AI in Business Processes

Automated Code Generation

You can generate CRUD operations, API endpoints, and admin interfaces with AI:

<?php

declare(strict_types=1);

namespace App\CodeGeneration;

use App\Contracts\AIClientInterface;
use App\Exceptions\CodeGenerationException;
use App\ValueObjects\{CodeTemplate, EntityName, FieldDefinition};
use Psr\Log\LoggerInterface;

final readonly class AICodeGenerator
{
    public function __construct(
        private AIClientInterface $aiClient,
        private LoggerInterface $logger,
        private CodeTemplateRepository $templateRepository,
    ) {
    }

    /** @param array<FieldDefinition> $fields */
    public function generateCRUD(EntityName $entityName, array $fields): string
    {
        $template = $this->templateRepository->getTemplate('modern-php-entity');
        $prompt = $this->buildPrompt($entityName, $fields, $template);

        try {
            $generatedCode = $this->aiClient->generateCode($prompt);

            $this->logger->info('CRUD code generated successfully', [
                'entity'       => $entityName->value,
                'fields_count' => count($fields),
            ]);

            return $this->postProcessCode($generatedCode);
        } catch (Throwable $e) {
            throw new CodeGenerationException(
                "Failed to generate CRUD for {$entityName->value}: {$e->getMessage()}",
                previous: $e
            );
        }
    }

    /** @param array<FieldDefinition> $fields */
    private function buildPrompt(EntityName $entityName, array $fields, CodeTemplate $template): string
    {
        $fieldDescriptions = array_map(
            fn (FieldDefinition $field) => $field->toPromptString(),
            $fields
        );

        return $template->render([
            'entity_name' => $entityName->value,
            'fields'      => implode(', ', $fieldDescriptions),
            'requirements' => [
                'Use PHP 8.3+ features',
                'Include strict typing with declare(strict_types=1)',
                'Use readonly properties where appropriate',
                'Include proper validation and error handling',
                'Follow domain-driven design principles',
                'Use value objects for complex data',
                'Include comprehensive PHPDoc',
            ],
        ]);
    }

    private function postProcessCode(string $code): string
    {
        // Post-process generated code to ensure consistency
        return $code;
    }
}

Intelligent Error Handling

AI can suggest solutions for common errors you encounter:

<?php

declare(strict_types=1);

namespace App\ErrorHandling;

use App\Contracts\AIClientInterface;
use App\Exceptions\ErrorAnalysisException;
use App\ValueObjects\{ErrorContext, ErrorSolution};
use Psr\Log\LoggerInterface;
use Throwable;

final readonly class AIErrorHandler
{
    public function __construct(
        private AIClientInterface $aiClient,
        private LoggerInterface $logger,
        private ErrorContextBuilder $contextBuilder,
    ) {
    }

    public function handleError(Throwable $error): ErrorSolution
    {
        $context = $this->contextBuilder->buildFromThrowable($error);

        try {
            $solution = $this->aiClient->suggestSolution($context);

            $this->logger->info('AI error solution generated', [
                'error_type'          => $error::class,
                'error_message'       => $error->getMessage(),
                'solution_confidence' => $solution->getConfidence(),
            ]);

            return $solution;
        } catch (Throwable $e) {
            $this->logger->error('Failed to generate AI solution', [
                'original_error' => $error->getMessage(),
                'ai_error'       => $e->getMessage(),
            ]);

            throw new ErrorAnalysisException(
                "Failed to analyze error: {$e->getMessage()}",
                previous: $e
            );
        }
    }

    public function analyzePerformanceIssue(string $slowQuery, array $metrics): ErrorSolution
    {
        $context = new ErrorContext(
            type: 'performance',
            description: 'Slow database query detected',
            metadata: [
                'query'          => $slowQuery,
                'execution_time' => $metrics['execution_time'],
                'memory_usage'   => $metrics['memory_usage'],
                'affected_rows'  => $metrics['affected_rows'],
            ]
        );

        return $this->aiClient->suggestSolution($context);
    }

    public function analyzeSecurityVulnerability(string $code, array $scanResults): ErrorSolution
    {
        $context = new ErrorContext(
            type: 'security',
            description: 'Security vulnerability detected',
            metadata: [
                'code_snippet'       => $code,
                'vulnerability_type' => $scanResults['type'],
                'severity'           => $scanResults['severity'],
                'cwe_id'             => $scanResults['cwe_id'] ?? null,
            ]
        );

        return $this->aiClient->suggestSolution($context);
    }
}

Measuring AI Impact

Track these metrics to see how AI impacts your development process:

  • Development speed: Time to implement features
  • Code quality: Bug reports, code review feedback
  • Test coverage: Automated test generation effectiveness
  • Developer satisfaction: Reduced repetitive tasks

Where AI-Generated PHP Goes Wrong

Over-reliance on AI

Don't let AI replace your brain:

  • Always understand the code you're implementing
  • Question AI suggestions and validate them
  • Maintain your core programming skills

Security Blindness

AI doesn't always generate secure code. Watch out for these issues:

  • Always review for SQL injection vulnerabilities
  • Check for proper input validation
  • Ensure sensitive data handling is correct

Performance Ignorance

AI-generated code isn't always fast. Check for these problems:

  • Profile generated code for performance bottlenecks
  • Consider database query efficiency
  • Optimise algorithms for your specific use case

The Future of AI in PHP Development

AI tools evolve fast. Stay ahead by:

  • Experimenting with new AI tools and models
  • Building custom AI integrations for your specific needs
  • Sharing knowledge with the PHP community
  • Balancing AI efficiency with human expertise

The pattern running through every example here is the same: use AI to generate a first draft, whether that's a prototype, a test suite, or a refactor, then apply the same scrutiny you'd give a junior developer's pull request, checking the output, the security implications, and the performance rather than taking any of it on trust. The tools save you time on the typing; they don't save you from understanding what the code actually does.

This is exactly the kind of problem the guardrail tooling below is built for.

See the open-source work