cd /news/large-language-models/learn-php-with-claude-in-2026-build-… Β· home β€Ί topics β€Ί large-language-models β€Ί article
[ARTICLE Β· art-46249] src=dev.to β†— pub= topic=large-language-models verified=true sentiment=Β· neutral

Learn PHP with Claude in 2026: build real skills, not AI dependency

A developer warns that AI-generated PHP code is creating a generation of Laravel operators who lack fundamental PHP knowledge, citing a case where a developer using Claude copied a controller that used `$request->all()` instead of `$request->validated()`, leaving a mass assignment vulnerability. The developer argues that PHP 8.3 is a modern, typed language powering 75% of the web, and that learners must understand core PHP concepts like `$_GET`, `$_POST`, and `password_hash()` before relying on frameworks or AI.

read10 min views1 publishedJul 1, 2026

Code review last week. A "fullstack" dev shows me his Laravel API. Clean on the surface β€” well-organized controllers, Eloquent migrations, Form Request validation. I ask him why he's using $request->all()

instead of $request->validated()

in his controller. Blank stare. He didn't know that all()

returns everything in the payload, including unvalidated fields. Claude generated the controller, he copied it, it worked. Six months of Laravel and a dormant mass assignment vulnerability in every endpoint.

PHP has a problem Python doesn't: its reputation. "Dead language," "spaghetti code," "only good for WordPress." In 2026, that's been wrong for a long time β€” PHP 8.3 is a typed, modern language with enums, fibers, readonly properties, and performance PHP 5 could never have imagined. But this reputation means many beginners skip the basics and jump straight to a framework, guided by AI. The result: Laravel operators, not PHP developers. This article explains how to use Claude to become the latter without falling into the former.

Before talking pedagogy, let's settle this. "Why learn PHP when everyone's moving to Go / Rust / TypeScript?" Three facts, not opinions.

1. PHP powers 75% of the web. WordPress, Shopify (backend), Symfony, Laravel β€” millions of projects in production. PHP gigs aren't scarce, and they pay well because good PHP devs are rare. Everyone wants to code in Rust; few can debug a Doctrine\ORM\Query\QueryException

at 2am.

2. PHP 8.3 has nothing in common with PHP 5. Type declarations, enums, readonly

, match

, named arguments, fibers, JIT β€” it's a different language. PHP criticism dates back to 2012. In 2026, the same patterns people applauded in TypeScript exist natively in PHP.

3. AI doesn't debug your business context. Claude generates a UserController

in 15 seconds. But when the client's LDAP auth breaks in staging and sessions no longer propagate between PHP-FPM workers, you're the one who needs to understand the HTTP request lifecycle. If you never understood $_SESSION

, you're stuck.

PHP has its own learning anti-patterns. AI amplifies them if you don't know they exist.

You ask "how to create a contact form in PHP," Claude gives you WordPress code with wp_mail()

and add_action

hooks. You copy, it works in WordPress. You learned nothing about PHP. You don't know that native mail()

exists, that it's terrible in production (no SMTP auth, no TLS), and that PHPMailer solves the real problem. WordPress is not PHP β€” it's a framework with its own dialect.

Laravel in week 1. It's the most common trap. The framework abstracts everything: routing, requests, responses, sessions, middleware. If you don't understand what $_GET

, $_POST

, $_SERVER['REQUEST_METHOD']

are, you don't understand what the framework does for you. And the day it does something unexpected, you're lost.

AI was trained on millions of lines of old PHP. When you ask "how to hash a password in PHP," there's a non-trivial chance Claude suggests md5()

or sha1()

in certain contexts. The right reflex: password_hash()

with PASSWORD_BCRYPT

or PASSWORD_ARGON2ID

. Always check the PHP version of suggested patterns.

// ❌ PHP 5 β€” NEVER do this
$hash = md5($password);
$hash = sha1($password . $salt);

// βœ… PHP 8 β€” the only right way
$hash = password_hash($password, PASSWORD_ARGON2ID);
$valid = password_verify($input, $hash);

PHP is optionally typed. AI often generates code without types because it's "simpler." Result: you learn a lenient PHP that accepts anything and crashes in production with TypeError

s you don't understand. Enable declare(strict_types=1)

from your very first file. No exceptions.

// ❌ No typing β€” everything passes, nothing is safe
function calculatePrice($quantity, $unitPrice) {
    return $quantity * $unitPrice;
}
calculatePrice("3", "19.99"); // Works... by accident

// βœ… With strict_types β€” errors are explicit
declare(strict_types=1);

function calculatePrice(int $quantity, float $unitPrice): float {
    return $quantity * $unitPrice;
}
calculatePrice("3", "19.99"); // Immediate TypeError

Claude sometimes suggests mysqli

, sometimes PDO

, depending on context. The real advice: use PDO

, period. It's the standard abstraction layer, it handles prepared statements cleanly, and it works with any database engine. mysqli

is MySQL-specific and brings nothing extra in 99% of cases.

// ❌ mysqli β€” coupled to MySQL, confusing API
$conn = new mysqli("localhost", "user", "pass", "db");
$stmt = $conn->prepare("SELECT * FROM users WHERE email = ?");
$stmt->bind_param("s", $email);
$stmt->execute();
$result = $stmt->get_result();

// βœ… PDO β€” portable, clear, chainable
$pdo = new PDO('mysql:host=localhost;dbname=db', 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();

The same cycle as for any language β€” I covered it in the Python guide β€” but with concrete PHP examples.

Problem: filter an array of users to keep only adults. Your first version, without AI:

// My version β€” filter adult users
function getAdults(array $users): array {
    $adults = [];
    foreach ($users as $user) {
        if ($user['age'] >= 18) {
            $adults[] = $user;
        }
    }
    return $adults;
}

Here's my PHP code to filter an array of users. Don't give me a corrected version. Tell me what could be improved and why, and let me rewrite it myself.

Claude will point out: array_filter

exists for this. The return type is array

but could be more precise with a @return array<int, array{name: string, age: int}>

docblock. And what if $users

is empty? Does your function handle that? (Yes, it does β€” but did you think about it?)

// My improved version after review
/** @param array<array{name: string, age: int}> $users */
function getAdults(array $users): array {
    return array_filter($users, fn(array $user): bool => $user['age'] >= 18);
}

You discovered array_filter

and arrow functions. You understand that fn() =>

is syntactic sugar for single-expression closures. You know why it's more concise, and you know that array_filter

preserves keys (which can be a trap if you then iterate with numeric indices).

Here's my improved version. What am I not seeing? Is there a more robust pattern for this kind of filtering?

Claude will probably mention the match

expression for multi-criteria filtering, typed collections with classes, and the difference between array_filter

and array_values(array_filter(...))

to reindex the array. Three levels of understanding, and you wrote the first two yourself.

The difference between learning and delegating comes down to how you phrase the prompt. Here are patterns adapted to PHP.

❌ Passive prompt

βœ… Pedagogical prompt

"Write a PHP CRUD for managing products"

"I wrote this POST route that inserts a product with PDO. Do my prepared statements really protect against SQL injection?"

"Fix this error"

"This code raises TypeError: Argument #1 must be of type string, null given

. Explain where the null

comes from without giving me the fix."

"Make me a Laravel auth"

"I implemented session auth with password_verify()

and a CSRF token. What could an attacker exploit?"

"What are namespaces?"

"I understand that use App\Service\UserService

imports a class. But what's the difference between use

in a namespace and use

in a closure?"

"Write a PHP class"

"I have this User

class with 8 constructor properties. Would PHP 8 promoted properties simplify it? Show me the difference."

The common pattern: show what you did or understood, then ask a specific question. Not "explain namespaces" but "I understood this much, what am I missing?". Claude adapts its response to your actual level instead of serving a long-form version of the PHP.net docs.

Not a rigid program β€” a path that worked for people I've mentored. Adapted to PHP specifics. AI comes in after the effort, never before.

Variables, types, conditions, loops, functions, arrays. Without Claude. Use the official PHP documentation (php.net/manual) and do the exercises by hand. Start every file with declare(strict_types=1)

. The goal: make foreach ($items as $key => $value)

a reflex, not a formula you ask for every time.

Exercise: write a script that reads a CSV file and calculates statistics (average, min, max) on a numeric column. No external library. Just fopen()

, fgetcsv()

, an associative array. When done, ask Claude for a review.

Classes, interfaces, traits, inheritance, composition, namespaces, PSR-4 auto. This is where PHP stands out: OOP is at the core of the modern language, and namespaces are the mechanism that structures any non-trivial project. Claude moves to review mode.

Exercise: a CLI task manager β€” add, delete, mark as "done," JSON export. Each entity in its own class. Use readonly

, constructor promoted properties, and enums for statuses. Write first, review with Claude after. It'll probably mention interfaces β€” that's the right moment.

// What you should write yourself in week 3
declare(strict_types=1);

enum TaskStatus: string {
    case Todo = 'todo';
    case Done = 'done';
    case Cancelled = 'cancelled';
}

final class Task {
    public function __construct(
        public readonly string $id,
        public readonly string $title,
        public TaskStatus $status = TaskStatus::Todo,
        public readonly \DateTimeImmutable $createdAt = new \DateTimeImmutable(),
    ) {}
}

Composer, auto, dependencies. PDO, prepared statements, manual migrations. Writing a minimal REST API β€” without a framework. Claude becomes a patterns teacher: "why separate routing from business logic?", "why not put SQL in the controller?".

Exercise: a REST API that manages blog posts (CRUD). Manual routing ($_SERVER['REQUEST_URI']

  • match

), PDO for the database, JSON in/out. HTTP error handling (404, 422, 500). Ask Claude: "is my routing secure?" β€” the answer will surprise you.

A project that combines everything. Two calibrated options:

Claude switches to pair programming mode: you write a feature, you discuss architecture with it, it challenges your choices. "Why put validation in the controller instead of a dedicated service?" β€” if you can't answer, you haven't consciously decided yet.

Two tools, two uses. Both cost $20/month (Claude Pro) or $20/month (Claude Code with the Max plan) β€” but the learning experience is very different.

Web interface, conversation. The right tool for:

abstract class

and interface

in PHP with a concrete case"===

and not ==

in PHP?"Advantage: accessible, no terminal needed, conversation history. Limitation: you copy-paste code, it can't see your composer.json

.

In the terminal, directly in your project. The right tool for:

composer.json

, your PHPUnit testsphp -S

, sees the error, explains the stack traceAdvantage: full project context, real execution. Limitation: more technical to set up, requires a terminal.

Weeks 1-4: Claude Pro for concepts and review. You don't have a complex project yet, the web interface is enough. Weeks 5-8: Claude Code for the project. You need file context, tests, live debugging. Claude Pro remains useful for conceptual questions in parallel.

Claude writes correct PHP. But there's a difference between correct code and professional code. These conventions are learned by reading good open source code (Symfony, Laravel, PHPStan) and getting corrected.

camelCase

for methods, PascalCase

for classes. Use PHP CS Fixer from day one.require

require_once 'lib/User.php'

, you're writing 2008 PHP. PSR-4 + composer dump-autoload

, period.new PDO(...)

in every method. That's a major anti-pattern.declare(strict_types=1)

everywhere"42abc"

to 42

. With it, it throws a TypeError

. You want the second behavior.array

holding structured data should be a DTO (Data Transfer Object) with typed properties. AI loves associative arrays. Resist.How to know if you're actually learning and not just "doing things with Claude"? Three concrete tests.

Test 1 β€” The whiteboard. Take a problem you solved with Claude last week. Rewrite the class from memory, no IDE, no AI. If you're stuck on promoted property constructor syntax, you didn't learn β€” you delegated.

Test 2 β€” The explanation. Explain your code to someone. Every method. If you say "this part with the match

I'm not sure why it's like that," that's a gap in your understanding.

Test 3 β€” Debugging without a net. Introduce a null

somewhere in your call chain. Close Claude. Find the TypeError

with var_dump()

, error_log()

, or just by reading the stack trace. The time it takes measures your real autonomy.

PHP isn't dead, it just grew faster than its reputation. The 2026 language β€” typed, with enums, readonly, match, fibers β€” has little in common with the PHP from Reddit jokes. But this modernity is useless if you discover it through copy-paste from Claude. The discipline stays the same: write first, ask second, rewrite yourself.

The developer who finishes this 8-week path knows how to read a stack trace, choose between an array and a DTO, write PSR-12 code others can read, and use Claude as a multiplier β€” not a crutch. That's exactly the profile the market is missing: someone who can code PHP and who knows how to get the most out of AI.

The same workflow applies to any language. If you're coming from Go, I wrote the equivalent guide for Go. For Python, it's over here.

── more in #large-language-models 4 stories Β· sorted by recency
── more on @claude 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/learn-php-with-claud…] indexed:0 read:10min 2026-07-01 Β· β€”