php
52 lines · 7 steps
A single-action JSON user controller in PHP
An invokable controller parses a JSON request, validates it, creates a user, and returns a structured response.
Explained by
highlit
1<?php
2
3declare(strict_types=1);
4
5namespace App\Http;
6
7final class CreateUserController
8{
9 public function __construct(private readonly UserRepository $users)
10 {
11 }
12
13 public function __invoke(): void
14 {
15 header('Content-Type: application/json');
16
17 $raw = file_get_contents('php://input');
18 $payload = json_decode($raw ?: '', true, 512, JSON_THROW_ON_ERROR);
19
20 if (!is_array($payload) || empty($payload['email']) || empty($payload['name'])) {
21 $this->respond(422, [
22 'error' => 'Validation failed',
23 'fields' => ['email', 'name'],
24 ]);
25 return;
26 }
27
28 $email = filter_var($payload['email'], FILTER_VALIDATE_EMAIL);
29
30 if ($email === false) {
31 $this->respond(422, ['error' => 'Invalid email address']);
32 return;
33 }
34
35 $user = $this->users->create(
36 name: trim((string) $payload['name']),
37 email: $email,
38 );
39
40 $this->respond(201, [
41 'id' => $user->id,
42 'name' => $user->name,
43 'email' => $user->email,
44 ]);
45 }
46
47 private function respond(int $status, array $body): void
48 {
49 http_response_code($status);
50 echo json_encode($body, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
51 }
52}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Constructor property promotion collapses dependency injection into a single readonly parameter.
- 2Validating and normalizing input before persisting keeps bad data out of the repository.
- 3Centralizing status codes and JSON encoding in one helper keeps every response consistent.
Related explainers
php
<?php namespace App\Services;
Building signed, expiring download URLs in PHP in Laravel
hmac
url-signing
authentication
Intermediate
7 steps
rust
use std::path::PathBuf; use clap::{Parser, Subcommand, ValueEnum};
Building a CLI with clap's derive macros
cli
derive-macros
argument-parsing
Intermediate
10 steps
rust
use std::sync::Arc; use axum::{ body::Body, extract::{Extension, State},
Passing per-request context through Axum middleware
middleware
request-context
dependency-injection
Intermediate
8 steps
php
<?php namespace App\Services\Provisioning;
Sequencing site setup with Laravel job chains
job chains
queues
async workflows
Intermediate
6 steps
java
public final class ShippingAddress { private final String recipient; private final String line1; private final String line2;
Building immutable objects with the Builder pattern
builder-pattern
immutability
validation
Intermediate
7 steps
php
final class UserActivityStream { public function __construct( private readonly \PDO $db,
Streaming user activity with PHP generators
generators
pagination
lazy-evaluation
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-single-action-json-user-controller-in-php-explained-php-1892/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.