This guide covers everything you need to know about generating PHP code using the CodeGenerationAgent.
The CodeGenerationAgent uses Claude to generate PHP code from natural language descriptions. It includes automatic validation and retry logic to ensure high-quality output.
use ClaudeAgents\Agents\CodeGenerationAgent;
use ClaudePhp\ClaudePhp;
$client = new ClaudePhp(apiKey: getenv('ANTHROPIC_API_KEY'));
$agent = new CodeGenerationAgent($client);
$result = $agent->generateComponent(
'Create a Calculator class with add, subtract, multiply, and divide methods'
);
echo $result->getCode();use ClaudeAgents\Validation\ValidationCoordinator;
use ClaudeAgents\Validation\Validators\PHPSyntaxValidator;
$validator = new ValidationCoordinator();
$validator->addValidator(new PHPSyntaxValidator());
$agent = new CodeGenerationAgent($client, [
'validation_coordinator' => $validator,
]);
$result = $agent->generateComponent('Create a Logger class');
if ($result->isValid()) {
$result->saveToFile('Logger.php');
}Fast syntax checking using php -l:
use ClaudeAgents\Validation\Validators\PHPSyntaxValidator;
$validator = new PHPSyntaxValidator();
$result = $validator->validate($code);PHPStan or Psalm integration:
use ClaudeAgents\Validation\Validators\StaticAnalysisValidator;
// PHPStan
$phpstan = StaticAnalysisValidator::phpstan(level: 6);
// Psalm
$psalm = StaticAnalysisValidator::psalm();Run custom validation scripts:
use ClaudeAgents\Validation\Validators\CustomScriptValidator;
// PHPUnit
$phpunit = CustomScriptValidator::phpunit('tests/MyTest.php');
// Pest
$pest = CustomScriptValidator::pest('tests/Feature/MyTest.php');
// Custom script
$custom = new CustomScriptValidator('php validate.php {file}');AI-powered code review:
use ClaudeAgents\Validation\Validators\LLMReviewValidator;
$llmValidator = new LLMReviewValidator($client);Validators run in priority order (lower = earlier):
$coordinator = new ValidationCoordinator();
$coordinator->addValidator(new PHPSyntaxValidator()); // Priority: 10
$coordinator->addValidator(StaticAnalysisValidator::phpstan()); // Priority: 20
$coordinator->addValidator($customValidator); // Priority: 30
$coordinator->addValidator(new LLMReviewValidator($client)); // Priority: 100When validation fails, the agent:
- Captures validation errors
- Creates an improved prompt with error feedback
- Regenerates the code
- Validates again
$agent = new CodeGenerationAgent($client, [
'max_validation_retries' => 3, // Try up to 3 times after initial attempt
]);$agent->onRetry(function (int $attempt, array $errors) {
echo "Retry attempt {$attempt}\n";
echo "Errors: " . implode(', ', $errors) . "\n";
});Attempt 1: Generate code
↓
Validate
↓
❌ Failed (syntax error)
↓
Attempt 2: Generate with error feedback
↓
Validate
↓
✅ Passed
The agent emits various events during execution:
code.generating- Code generation startedcode.generated- Code generation completedvalidation.started- Validation beganvalidation.passed- Validation succeededvalidation.failed- Validation failedretry.attempt- Retry attempt numberretry.reframing- Prompt being reframedcomponent.completed- Final component ready
$agent->onUpdate(function (string $type, array $data) {
$timestamp = date('H:i:s');
match ($type) {
'code.generating' => echo "[{$timestamp}] 🔄 Generating code...\n",
'code.generated' => echo "[{$timestamp}] ✅ Generated {$data['line_count']} lines\n",
'validation.started' => echo "[{$timestamp}] 🔍 Validating...\n",
'validation.passed' => echo "[{$timestamp}] ✅ Passed!\n",
'validation.failed' => echo "[{$timestamp}] ❌ Failed: {$data['errors'][0]}\n",
'retry.attempt' => echo "[{$timestamp}] 🔄 Retry {$data['attempt']}\n",
'component.completed' => echo "[{$timestamp}] 🎉 Complete!\n",
default => null,
};
});$agent->onValidation(function (ValidationResult $result, int $attempt) {
if ($result->isValid()) {
echo "Validation passed on attempt {$attempt}\n";
} else {
echo "Validation failed:\n";
foreach ($result->getErrors() as $error) {
echo " - {$error}\n";
}
}
});Generate code from templates:
use ClaudeAgents\Generation\ComponentTemplate;
// Class template
$class = ComponentTemplate::classTemplate(
name: 'User',
namespace: 'App\\Models',
options: [
'properties' => [
['name' => 'id', 'type' => 'int', 'visibility' => 'private'],
['name' => 'name', 'type' => 'string', 'visibility' => 'private'],
],
'methods' => [
[
'name' => 'getId',
'return_type' => 'int',
'body' => " return \$this->id;\n",
],
],
]
);
// Interface template
$interface = ComponentTemplate::interfaceTemplate(
name: 'RepositoryInterface',
namespace: 'App\\Contracts'
);
// Service template with dependencies
$service = ComponentTemplate::serviceTemplate(
name: 'UserService',
namespace: 'App\\Services',
options: [
'dependencies' => [
['name' => 'repository', 'type' => 'UserRepository'],
['name' => 'logger', 'type' => 'LoggerInterface'],
],
]
);// ❌ Vague
$result = $agent->generateComponent('Create a user class');
// ✅ Specific
$result = $agent->generateComponent(
'Create a User class with properties: id (int), name (string), email (string).
Include getters, setters, and a constructor with all properties as parameters.'
);$context = [
'namespace' => 'App\\Services',
'framework' => 'Laravel',
'php_version' => '8.2',
'use_attributes' => true,
];
$result = $agent->generateComponent($description, $context);// For simple code: faster, cheaper
$agent = new CodeGenerationAgent($client, [
'model' => 'claude-haiku-3-5',
]);
// For complex code: more capable
$agent = new CodeGenerationAgent($client, [
'model' => 'claude-sonnet-4-5',
]);use ClaudeAgents\Validation\Exceptions\MaxRetriesException;
try {
$result = $agent->generateComponent($description);
if ($result->isValid()) {
$result->saveToFile('Generated.php');
}
} catch (MaxRetriesException $e) {
// Max retries exceeded
$lastErrors = $e->getLastErrors();
// Handle or log errors
} catch (\Throwable $e) {
// Other errors
error_log($e->getMessage());
}$coordinator = new ValidationCoordinator();
// Syntax check (fast)
$coordinator->addValidator(new PHPSyntaxValidator());
// Static analysis (catch type errors)
$coordinator->addValidator(StaticAnalysisValidator::phpstan(level: 8));
// LLM review (catch logic issues)
$coordinator->addValidator(new LLMReviewValidator($client));
$agent = new CodeGenerationAgent($client, [
'validation_coordinator' => $coordinator,
'max_validation_retries' => 3,
]);$result = $agent->generateComponent($description);
if ($result->isValid()) {
// Save with timestamp
$filename = 'Generated_' . date('Ymd_His') . '.php';
$result->saveToFile("generated/{$filename}");
// Add to version control
exec("git add generated/{$filename}");
exec("git commit -m 'Generated: {$description}'");
}See the examples directory for complete working examples:
code_generation_example.php- Basic code generationvalidation_example.php- Validation system usagesse_streaming_example.php- Real-time streamingcomponent_generator_example.php- Using templates