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
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
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.