PHP Code
Type key: php_code_node
Group: Utilities
Category: utility
Tier: CORE
The PHP Code node executes arbitrary PHP code inside a sandboxed closure. It provides direct access to the current $input data array and the $context (ExecutionContext), making it the most powerful and flexible node for custom logic that cannot be expressed through the standard node library.
Handles
| Handle | Direction | Description |
|---|---|---|
input | Input | Data passed as $input inside the code closure |
output | Output | Emits whatever value is returned by the return statement |
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
code | string | return $input; | PHP code string to execute; <?php tag is stripped automatically |
output_fields | array | [] | Optional list of field names to extract from the return value; if empty, the full return value is emitted |
Execution Environment
The code is executed inside a PHP closure, providing access to:
| Variable | Type | Description |
|---|---|---|
$input | array | The incoming data array |
$context | ExecutionContext | Full execution context (variables, credentials, run metadata) |
The closure signature is:
$fn = function (array $input, ExecutionContext $context) {
// your code here
return $result;
};The return statement value becomes the node's output. Any PHP type is accepted: array, string, int, bool, or null.
Code Preprocessing
Before execution, the engine:
- Strips a leading
<?phptag if present - Wraps the code in a closure that binds
$inputand$context - Evaluates the closure with
eval() - Catches any
Throwableand returnsExecutionResult::failure()with the exception message
Context API
Inside the code, $context exposes:
// Read a workflow variable
$tenantId = $context->getVariable('tenant_id');
// Set a workflow variable
$context->setVariable('processed_count', 42);
// Access execution metadata
$runId = $context->executionId;
$workflow = $context->workflow;
// Access credentials (returns a CredentialProxy)
// Use ->execute() with an action such as 'get_auth_headers', 'get_api_client', etc.
$credential = $context->getCredential('my_api_credential');
$headers = $credential->execute('get_auth_headers');Examples
Passthrough (Default)
return $input;Data Transformation
return [
'full_name' => $input['first_name'] . ' ' . $input['last_name'],
'email_lower' => strtolower($input['email']),
'age' => (int) $input['age'],
'is_adult' => (int) $input['age'] >= 18,
];Conditional Logic
$discount = 0;
if ($input['total'] > 500) {
$discount = 0.15;
} elseif ($input['total'] > 100) {
$discount = 0.05;
}
return array_merge($input, [
'discount_rate' => $discount,
'discounted_total' => round($input['total'] * (1 - $discount), 2),
]);Using Laravel Helpers
use Illuminate\Support\Str;
return [
'slug' => Str::slug($input['title']),
'uuid' => Str::uuid()->toString(),
'excerpt' => Str::limit($input['body'], 160),
'timestamp' => now()->toIso8601String(),
];Calling an Eloquent Model
$user = \App\Models\User::find($input['user_id']);
if (! $user) {
return ['found' => false];
}
return [
'found' => true,
'name' => $user->name,
'plan' => $user->subscription?->plan,
'is_admin' => $user->hasRole('admin'),
];HTTP Request with Guzzle
$credential = $context->getCredential('openai');
$authHeaders = $credential->execute('get_auth_headers');
$response = \Illuminate\Support\Facades\Http::withHeaders($authHeaders)
->post('https://api.openai.com/v1/embeddings', [
'model' => 'text-embedding-3-small',
'input' => $input['text'],
]);
return $response->json();Aggregate Calculation
$items = $input['items'] ?? [];
$subtotal = array_sum(array_column($items, 'price'));
$vat = round($subtotal * 0.22, 2);
return [
'items' => $items,
'subtotal' => $subtotal,
'vat' => $vat,
'total' => round($subtotal + $vat, 2),
];output_fields Filtering
When output_fields is set, only the specified keys are emitted:
output_fields: [full_name, email_lower]Given a return value of ['full_name' => 'John Doe', 'email_lower' => 'john@example.com', 'raw' => '...'], only full_name and email_lower will be forwarded downstream.
Error Handling
Any exception or fatal error thrown inside the code is caught by the engine:
throw new \RuntimeException("Custom error: {$input['id']} not processable");The node emits ExecutionResult::failure() with:
error_message: The exception messageerror_code:PHP_CODE_EXCEPTION
Use a Catch node to handle these failures.
Security Considerations
Warning: The PHP Code node executes arbitrary PHP via
eval(). It should be accessible only to trusted administrators.
- Restrict access using Filament Shield policies; do not expose it to end-users
- Avoid storing sensitive credentials directly in
code; use$context->getCredential()instead - In multi-tenant environments, ensure workflow editing is limited to trusted roles
Notes
- The node is ideal for one-off transformations that would require multiple standard nodes to express
- For recurring, complex logic, consider creating a Custom Node instead
eval()operates in the same PHP process and memory space — heavy operations can impact performance; offload to queues- All Laravel facades, Eloquent models, and helpers are available in scope