PHP Cheat Sheet
Server-side language for websites, forms, APIs and databases. This sheet targets PHP 8.4 and marks features that need PHP 8.0 or later.
On this page
Running PHP #
| Command | What it does |
|---|---|
php file.php | Run a script in the terminal |
php -S localhost:8000 -t public | Built-in web server with public as web root (development only) |
php -a | Interactive shell |
php -l file.php | Check a file for syntax errors |
composer require vendor/package | Install a package into vendor/ (composer install restores from composer.lock) |
require __DIR__ . '/vendor/autoload.php'; | Load Composer packages in your code |
Variables & Types #
| Code | What it does |
|---|---|
<?php | Opening tag; leave out the closing ?> in PHP-only files |
<?= $name ?> | Short echo tag inside HTML |
$name = "Milan"; | Variables start with $, no declaration needed |
echo "Hi", PHP_EOL; | Print one or more values (print takes one) |
const MAX = 10; | Constant (old style: define('MAX', 10)) |
var_dump($x); / print_r($arr); | Show type and value / readable dump of an array |
(int) "42" | Cast; also (float), (string), (bool), (array) |
is_int($x) / is_string($x) / get_debug_type($x) | Type checks / type name (PHP 8.0+) |
isset($x) / empty($x) | Exists and is not null / missing or falsy ("", "0", 0, [], null) |
declare(strict_types=1); | First statement of a file: wrong scalar types throw TypeError instead of being converted |
function f(?string $s): int | Parameter and return types; ? = nullable |
int|float / mixed / never | Union type / any type (PHP 8.0+) / never returns (PHP 8.1+) |
Strings #
| Code | What it does |
|---|---|
'Hi $name\n' | Single quotes: literal text, no variables or escapes |
"Hi $name\n" | Double quotes: variables and escapes are expanded |
"Total: {$order['total']}" | Braces for array keys, properties and method calls |
"a" . "b" / $s .= "c"; | Concatenate / append |
strlen($s) / mb_strlen($s) | Length in bytes / in characters (use mb_ for é, ü) |
strtoupper($s) / ucfirst($s) / ucwords($s) | Uppercase / first letter / each word |
trim($s) | Strip whitespace from both ends (ltrim, rtrim) |
str_contains($s, "x") | Contains substring (also str_starts_with, str_ends_with) (PHP 8.0+) |
strpos($s, "x") | Position of first match, or false |
substr($s, 0, 5) / substr($s, -3) | Part of a string / last 3 characters |
str_replace("a", "b", $s) | Replace all occurrences |
explode(",", $s) / implode(", ", $arr) | Split into an array / join into a string |
sprintf("%s: %.2f", $name, $price) | Formatted string (printf prints it) |
number_format(1234.5, 2, ',', '.') | "1.234,50" |
<<<HTML ... HTML; | Heredoc: multi-line string, works like double quotes |
<<<'TXT' ... TXT; | Nowdoc: multi-line string, works like single quotes |
preg_match('/(\d+)/', $s, $m) / preg_replace('/\s+/', ' ', $s) | Regex match (groups in $m) / regex replace |
Operators #
| Code | What it does |
|---|---|
=== / !== | Same value and type (use these; == juggles types: "1" == "01" is true) |
$a <=> $b | Spaceship: -1, 0 or 1 (handy for sorting) |
$x ?? 'default' | Null coalescing: $x if set and not null, else the default |
$x ??= [] | Assign only if $x is null or unset |
$user?->address?->city | Nullsafe: returns null instead of failing on null (PHP 8.0+) |
$a ?: $b | $a if truthy, else $b |
&& / || / ! | And / or / not |
2 ** 10 / intdiv(7, 2) / 7 % 2 | Power (1024) / integer division (3) / remainder (1) |
Control Flow #
| Code | What it does |
|---|---|
if (...) { } elseif (...) { } else { } | Conditions |
match ($x) { 1, 2 => 'low', default => 'high' } | Returns a value, strict ===, no break; no match throws UnhandledMatchError (PHP 8.0+) |
match (true) { $age < 18 => 'minor', default => 'adult' } | Match conditions instead of values |
switch ($x) { case 1: ...; break; } | Older style: loose == comparison, needs break |
for ($i = 0; $i < 10; $i++) { } / while (...) { } | Counting loop / condition loop (break, continue) |
foreach ($items as $key => $value) { } | Loop over an array (as $value for values only) |
if (...): ... endif; | Template syntax (also foreach: ... endforeach;) |
Arrays #
| Code | What it does |
|---|---|
$nums = [1, 2, 3]; / $nums[] = 4; | Indexed array / append |
$user = ['name' => 'Ann', 'age' => 30]; | Associative array (key => value) |
count($arr) | Number of elements |
in_array(2, $nums, true) | Value exists (true = strict comparison) |
array_key_exists('age', $user) | Key exists, even if its value is null |
array_keys($arr) / array_values($arr) | All keys / values re-indexed from 0 |
array_map(fn($n) => $n * 2, $nums) | Transform every element |
array_filter($nums, fn($n) => $n > 1) | Keep matching elements (keeps the original keys) |
array_reduce($nums, fn($c, $n) => $c + $n, 0) | Reduce to one value (or just array_sum($nums)) |
array_merge($a, $b) / [...$a, ...$b] | Merge; later string keys win (spread with string keys PHP 8.1+) |
array_column($rows, 'name', 'id') | One column from a list of rows, keyed by id |
sort($a) / asort($a) / ksort($a) | Sort values (re-indexes) / by value keeping keys / by key |
usort($rows, fn($x, $y) => $x['age'] <=> $y['age']) | Sort with your own comparison |
[$a, $b] = [1, 2]; / ['name' => $name] = $user; | Destructure by position / by key |
array_find($nums, fn($n) => $n > 2) | First matching value or null (also array_any, array_all) (PHP 8.4+) |
Functions #
| Code | What it does |
|---|---|
function greet(string $name = "World"): string { } | Typed parameter with a default value |
greet(name: "Ann") | Named arguments, any order, skip optional ones (PHP 8.0+) |
function sum(int ...$nums) / sum(...$list) | Variadic: extra arguments arrive as an array / unpack an array into arguments |
function add(array &$arr) | Pass by reference: changes affect the caller's variable |
$double = fn($x) => $x * 2; | Arrow function; reads outer variables automatically |
function ($x) use ($factor) { return $x * $factor; } | Closure; use copies outer variables in (use (&$n) by reference) |
strlen(...) | First-class callable: turns a function into a Closure (PHP 8.1+) |
static $calls = 0; | Local variable that keeps its value between calls |
Classes #
class User
{
public function __construct(
public readonly string $name, // promoted property (8.0+), readonly (8.1+)
private int $age = 0,
) {}
public function isAdult(): bool { return $this->age >= 18; }
}
$u = new User('Ann', 30); // $u->name
| Code | What it does |
|---|---|
public / protected / private | Visible everywhere / in the class and children / only in this class |
class Admin extends User | Inheritance; call the parent with parent::__construct(...) |
abstract class Shape / final class Circle | Can't be created directly / can't be extended |
const VERSION = '1.0'; | Class constant, read with User::VERSION |
public static function create(): static | Static method: User::create(); inside, use self:: / static:: |
readonly class Point | Every property is readonly (PHP 8.2+) |
new User('Ann')->isAdult() | No extra parentheses needed around new (PHP 8.4+) |
public private(set) int $balance = 0; | Asymmetric visibility: public read, private write (PHP 8.4+) |
public string $email { set => strtolower($value); } | Property hook runs on every write (PHP 8.4+) |
Interfaces, Traits & Enums #
interface HasArea { public function area(): float; }
trait Loggable { public function log(string $m): void { echo static::class . ": $m"; } }
final class Circle implements HasArea {
use Loggable; // copy the trait's methods in
public function __construct(private float $r) {}
public function area(): float { return M_PI * $this->r ** 2; }
}
enum Status: string { case Active = 'active'; case Banned = 'banned'; } // PHP 8.1+
| Code | What it does |
|---|---|
enum Suit { case Hearts; case Spades; } | Pure enum without values (PHP 8.1+) |
Status::Active->value / Suit::Hearts->name | 'active' / 'Hearts' |
Status::from('active') / Status::tryFrom('x') | Case from a value; ValueError / null if invalid |
Status::cases() | Array of all cases |
Errors & Exceptions #
| Code | What it does |
|---|---|
try { } catch (NotFoundException $e) { } finally { } | Catch an exception; finally always runs |
catch (TypeError | ValueError $e) | Several types in one catch |
catch (Throwable $e) | Catch everything, including Error (TypeError, DivisionByZeroError) |
throw new InvalidArgumentException("Bad id"); | Throw an exception (custom: class NotFound extends Exception {}) |
$e->getMessage() / $e->getCode() / $e->getLine() | Details of the exception |
$id ?? throw new Exception('Missing id') | throw as an expression (PHP 8.0+) |
error_reporting(E_ALL); ini_set('display_errors', '1'); | Show every error during development |
Forms & Superglobals #
| Code | What it does |
|---|---|
$_GET['q'] ?? '' | Query string value from ?q=... |
$_POST['email'] ?? '' | Field from a form sent with method="post" |
$_SERVER['REQUEST_METHOD'] === 'POST' | Was the form submitted? |
session_start(); $_SESSION['user'] = $id; | Session data that survives between requests |
<?= htmlspecialchars($name) ?> | Escape text for HTML output (prevents XSS) |
filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) | Int, false if invalid, null if missing |
filter_var($email, FILTER_VALIDATE_EMAIL) | The email, or false |
password_hash($pw, PASSWORD_DEFAULT) / password_verify($pw, $hash) | Store and check passwords safely |
header('Location: /thanks.php'); exit; | Redirect (before any output) |
Files, JSON & Dates #
| Code | What it does |
|---|---|
file_get_contents('data.txt') | Read a whole file into a string |
file_put_contents('log.txt', $line, FILE_APPEND) | Write a file (append with the flag) |
file_exists($p) / is_dir($p) / unlink($p) | Check a path / is it a folder / delete a file |
__DIR__ . '/config.php' | Path relative to the current file |
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) | PHP value to JSON text |
json_decode($json, true) | JSON to associative array (without true: objects) |
json_decode($json, true, flags: JSON_THROW_ON_ERROR) | Throw JsonException on bad JSON instead of returning null |
date('Y-m-d H:i:s') / time() | Now as formatted text / Unix timestamp |
new DateTimeImmutable('2026-10-11') | Date object (immutable: methods return a new one) |
$d->modify('+1 week')->format('d/m/Y') | Date math and formatting |
$a->diff($b)->days | Days between two dates |
Databases (PDO) #
$pdo = new PDO('mysql:host=localhost;dbname=shop;charset=utf8mb4', $user, $pass, [
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // errors throw by default (8.0+)
]);
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]); // value sent separately: no SQL injection
$user = $stmt->fetch(); // one row, or false
$pdo->prepare('INSERT INTO users (name, email) VALUES (?, ?)')->execute([$name, $email]);
$id = $pdo->lastInsertId();
| Code | What it does |
|---|---|
new PDO('sqlite:' . __DIR__ . '/app.db') | Connect to an SQLite file |
$stmt->fetchAll() / $stmt->fetchColumn() | All rows / first column of the next row (for COUNT(*)) |
$pdo->beginTransaction() / commit() / rollBack() | All-or-nothing changes |
Tips #
- Put
declare(strict_types=1);at the top of every file and compare with===. - Never trust
$_GET,$_POSTor$_COOKIE: validate input, escape output withhtmlspecialchars, and always use prepared statements for SQL. - Hash passwords with
password_hash(); nevermd5()orsha1(). strpos()returns0for a match at the start: test with!== false, or usestr_contains().- After
foreach ($arr as &$v), callunset($v), or a later loop over$arroverwrites its last element. php -Sanddisplay_errorsare for development only; log errors in production.
Nothing on this sheet matches “”.