Introduction

PHP coding means writing programs that run on a web server to generate dynamic responses over HTTP. In practice you are reading inputs (URL, form, JSON), doing work (validations, database queries, services), and writing outputs (HTML/JSON/images). 
PHP began as a templating layer but matured into a modern language with strict typing, attributes, enums, fibers, JIT optimizations, and a professional build toolchain. In 2025 developers build everything from content sites and APIs to SaaS dashboards and microservices with PHP.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Why PHP still dominates the web

A practical combination of easy hosting, mature CMSes, batteries‑included frameworks, and an enormous package ecosystem keeps PHP everywhere. Shared hosting still makes the first deploy trivial, while containers and managed clouds make scaling predictable. Composer standardised dependency management, PSR guidelines unified interfaces, and tools such as PHPUnit, PHPStan and PHP-CS-Fixer brought engineering rigor.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

How PHP executes a request

A browser sends an HTTP request. The web server (Apache/Nginx) forwards it to PHP-FPM. PHP bootstraps your app (autoload, config, routes), runs your controller or action, talks to services (databases, caches, queues, third‑party APIs), renders a response (HTML/JSON), and returns it to the web server, which sends it back to the browser. Each request is isolated, making memory leaks less catastrophic and horizontal scale straightforward.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Language fundamentals (syntax quick tour)

• Variables: $var; arrays: $a = ['x' => 1]; control: if/else/for/foreach/while. 
• Functions with types: function add(int $a, int $b): int { return $a+$b; }
• Classes and objects with visibility (public/protected/private), interfaces and traits.
• Namespaces prevent collisions; PSR‑4 maps namespaces to folder paths for autoloading.
• Exceptions and try/catch for errors; Throwable makes fatal-like errors catchable.
• Closures and arrow functions enable functional patterns; attributes provide native metadata.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Types and strictness

Turn on strict types (`declare(strict_types=1);`) and annotate parameters, properties and return types. Use union and nullable types to capture intent precisely. Enumerations (8.1+) formalize domain values; readonly properties model immutability. Static analysis (PHPStan/Psalm) plus tests yields confident refactors and fewer production bugs.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Modern PHP (8.0 → 8.4) highlights

PHP 8 brought JIT and attributes; 8.1 added enums & readonly; 8.2 refined types; 8.3 added typed class constants and json_validate(); 8.4 delivered property hooks, asymmetric visibility, new array helpers and DOM updates. Performance keeps improving and the standard library grows carefully. The language today feels expressive, safe, and pleasantly boring in production—the good kind of boring.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Composer & autoloading

Composer is the dependency manager. You declare packages in composer.json with version constraints; Composer resolves compatible versions for your environment and generates an autoloader. PSR‑4 autoloading maps namespaces to directories, so `App\Http\Controllers\HomeController` is discovered automatically based on folder structure. Daily workflows—installing libraries, updating security patches, generating optimized autoloaders—revolve around Composer.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Frameworks (Laravel, Symfony, Slim)

Frameworks standardize HTTP routing, controllers, validation, templating, database access and testing. Laravel prioritizes developer experience (Artisan CLI, Eloquent ORM, queues, Horizon, Breeze/Jetstream starters). Symfony offers robust components behind many projects, and Slim is excellent for micro‑APIs. Whether you pick full‑stack or micro, the patterns are similar: a front controller, dependency container, middleware pipeline, controllers, and views/templates.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Database access (PDO/ORM)

PDO is the native database abstraction with prepared statements, transactions and exceptions. Query builders and ORMs raise the abstraction: Eloquent (Laravel) and Doctrine (standalone/Symfony) help model relations, eager‑load to avoid N+1, and keep code expressive. Use migrations for schema changes, seeders for fixtures, and repositories/services for business logic.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Security essentials

• Escape output to avoid XSS. • Use CSRF tokens for state‑changing endpoints. • Hash passwords with password_hash() using Argon2id/bcrypt and verify with password_verify(). • Never interpolate raw input in SQL—use prepared statements. • Validate and normalize input. • Enforce rate limits and login throttles. • Keep dependencies patched; audit Composer lock for vulnerabilities. • Keep secrets outside version control; rotate keys; restrict filesystem permissions.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Performance & caching

Enable OPcache. Profile hotspots (Xdebug/Blackfire). Cache expensive fragments and whole responses where safe. Use Redis for application cache, sessions and queues. Avoid N+1 queries; index well; paginate. Minify assets, compress responses, lazy‑load images, and set far‑future cache headers for static files. Tune FPM workers and max_children to match CPU/memory.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Testing & quality

Adopt PHPUnit (or Pest) for unit/integration tests. Add static analysis (PHPStan/Psalm), code style (PHP-CS-Fixer), and security scanners to CI. Favor deterministic tests that don’t hit real networks or disks unless you specifically test integrations. Add smoke tests for key pages and health endpoints. Testing plus static analysis lets you ship faster with fewer regressions.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

DevOps & deployment

For small sites, shared or managed PHP hosting is fine. For teams, containerize to lock versions and extensions. A minimal stack: Nginx reverse proxy, PHP‑FPM container (your app), database container, and optionally Redis. Add migrations to deploy pipelines, health checks, structured logs, metrics and alerts. Use rolling or blue‑green deploys, keep backups and a tested restore plan.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Observability

Log context-rich events (user ID, request ID). Count request rates, latencies, and error ratios. Export metrics and set SLOs/alerts. Use tracing to see which queries or external calls dominate latency. Observability closes the loop so performance work targets facts, not hunches.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Common pitfalls & patterns

Avoid fat controllers; put business rules into services and actions. Separate write models from read models where needed. Be careful with time zones—store timestamps in UTC. Treat external APIs and the database as unreliable—use timeouts, retries, circuit breakers. Model validation rules once and reuse them at the API boundary and the UI. Document behavior with tests.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Hands‑on examples

Routing example (Slim/Laravel‑like), prepared PDO query, a simple controller, and a PHPUnit test. Expand with validation, authentication and error handling to form an end‑to‑end vertical slice. Package with Composer and Docker so it runs the same on every machine.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.

Learning path (90 days)

• Weeks 1–2: Syntax, types, arrays, control flow, functions, classes. 
• Weeks 3–4: HTTP requests, forms/JSON, cookies/sessions, PDO & prepared statements. 
• Weeks 5–6: Composer/PSR‑4, framework basics (routing, controllers, views), MVC. 
• Weeks 7–8: ORM, validation, file uploads, email, queues, caching. 
• Weeks 9–10: Tests, static analysis, CI, Docker. 
• Weeks 11–12: Security, profiling, logging/metrics, deploy to VPS/cloud.


Tip: Prefer dependency injection over singletons and facades where possible to keep code testable.

Tip: Fail fast with clear exceptions and typed results; validate at the edges of the system.

Note: Stick to PSR recommendations (PSR‑1/PSR‑12 coding style, PSR‑4 autoloading, PSR‑7 HTTP messages, PSR‑11 containers).

Practice: Add logging around external I/O (DB, HTTP) with elapsed time to spot slow calls quickly.

Practice: Store env‑specific secrets in environment variables or a secrets manager, not in the repo.

Design: Keep controllers thin; model business logic in services with clear interfaces and tests.