DS DevShelfHub Projects · AI tools
Cheatsheets / PHP
Cheatsheet · Languages

PHP: Types, Arrays, Classes, Namespaces and Composer Reference Guide

By DevShelfHub

Types, arrays, strings, classes, namespaces, Composer, attributes, enums, fibers, error handling — the modern PHP 8.3+ surface.

120 items 8 min Types Composer Enums

Start hereQuick start · 6 you’ll reach for daily

Strict modedeclare(strict_types=1);
Class fieldpublic readonly string $id
Matchmatch($x) { 1 => 'a', default => 'b' }
Nullsafe$user?->profile?->name
Composecomposer require …
Dev serverphp -S 127.0.0.1:8000 -t public

Target versions · paceVersions

Targets: php ≥ 8.3 composer ≥ 2.7 OPcache + JIT enabled PSR autoloading (PSR-4)

PHP 8.x is a different language from PHP 5/7 era code — typed properties, enums, attributes, first-class callables, readonly classes, fibers, and JIT compilation. Always start a file with declare(strict_types=1); — without it, "int $x" still accepts strings. Modern frameworks: Laravel / Symfony for full-stack, Slim / Hyperf for micro / async. Static analysis is mandatory — PHPStan at level 8 or Psalm catches what the runtime won’t.

Install · ComposerSetup

bash
# Install
brew install php@8.3                   # macOS
sudo apt install php8.3-cli php8.3-mbstring php8.3-curl php8.3-xml
# Windows: https://windows.php.net/download/

# Composer (the dep manager)
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# New project
mkdir myapp && cd myapp
composer init                          # interactive — fills composer.json
composer require slim/slim guzzlehttp/guzzle
composer require --dev phpunit/phpunit phpstan/phpstan

# Run
php -S 127.0.0.1:8000 -t public        # built-in dev server
php script.php                         # run a CLI script

# Daily commands
composer dump-autoload                 # regenerate autoloader
vendor/bin/phpunit
vendor/bin/phpstan analyse --level=max src
vendor/bin/php-cs-fixer fix

PSR-4 · autoloadingFiles & namespaces

<?php declare(strict_types=1);Every PHP file starts here. Don’t close with ?> in pure-PHP files.
namespace App\Models;Namespace declaration. Must be first non-declare statement.
use App\Services\Mailer;Import a class. Aliases via use Foo as Bar.
use function App\Util\slugify;Import a function.
use Foo\{A, B, C};Group use. Cleaner imports.
require __DIR__ . '/vendor/autoload.php';Bootstrap Composer’s autoloader.
composer.json autoload.psr-4Map App\\src/ directory.
spl_autoload_register(…)Custom autoloader. Composer handles this for you.

Scalars · unions · nullableTypes

Scalars

$x = 5;Local. Sigils are required.
int, float, string, bool, array, object, mixedBuilt-in scalar / aggregate types.
?intNullable int. Equivalent to int|null.
int|stringUnion type.
A&BIntersection type. Must satisfy both.
true, false, nullLiteral types (PHP 8.2+).
neverBottom type. For functions that always throw / exit.
voidReturns nothing. Don’t use return $x;.
self, static, parentIn method signatures — this class, late-static-bound, parent class.

Strings

"hi $name" / "hi {$obj->name}"Double-quoted interpolation. Braces for expressions.
'no interp'Single-quoted literal.
<<<SQL … SQLHeredoc — interpolates. <<<'SQL' = nowdoc, literal.
str_starts_with / str_contains / str_ends_withModern string tests (PHP 8+). Replace strpos comparisons.
strlen / mb_strlenBytes vs multi-byte chars. Use mb_* for UTF-8.
sprintf / printfprintf-style formatting.
preg_match / preg_replace / preg_match_allPCRE regex. Delimiters required: '/…/'.

Indexed · associativeArrays

[1, 2, 3]Indexed.
['name' => 'Ada', 'age' => 36]Associative.
$xs[] = 4;Append.
[...$xs, 5, 6]Spread in literals.
[$a, $b, $rest] = [1, 2, [3, 4]];Destructure with index.
['name' => $n] = $user;Destructure by key.
array_map(fn($x) => $x * 2, $xs)Map.
array_filter($xs, fn($x) => $x > 0)Filter. Preserves keys.
array_reduce($xs, fn($acc, $x) => $acc + $x, 0)Fold.
array_keys / array_values / array_combineStructural ops.
array_merge($a, $b) vs $a + $b+ keeps left keys; merge overwrites for string keys.
array_unique / array_flip / array_reverseDedupe / swap keys&values / reverse.
array_column($rows, 'name', 'id')Pluck a column, key by another. Underused gem.
sort / asort / ksortIn-place. Reset keys / preserve / by key.

Worked example

php
 36, 'grace' => 85];

// Spread + destructuring
$more = [...$nums, 5, 6];
[$a, $b, $rest] = [1, 2, [3, 4]];
['ada' => $age] = $users;              // named destructure

// Common helpers
$doubled = array_map(fn($x) => $x * 2, $nums);
$evens   = array_filter($nums, fn($x) => $x % 2 === 0);
$sum     = array_reduce($nums, fn($acc, $x) => $acc + $x, 0);

// Indexed vs associative
$names = array_keys($users);
$ages  = array_values($users);
$has   = array_key_exists('ada', $users);
sort($nums);                            // mutates! in-place

// Grouping
$grouped = [];
foreach ($users as $name => $age) {
    $bucket = $age >= 50 ? 'senior' : 'junior';
    $grouped[$bucket][] = $name;
}
print_r($grouped);

// First-class callable syntax (PHP 8.1+)
$upper = strtoupper(...);
echo $upper('hello');                   // "HELLO"

if · match · loopsControl flow

if ($x > 0) { … } elseif … else { … }Standard.
$y = $x > 0 ? 'pos' : 'neg';Ternary.
$y = $x ?? 'default';Null-coalesce.
$obj?->prop?->method()Nullsafe chain.
switch ($x) { case 1: … break; default: … }Legacy Old form. Falls through. Prefer match.
$y = match ($x) { 1 => 'a', 2, 3 => 'b', default => 'c' };Preferred Strict comparison, no fallthrough, returns a value.
for ($i = 0; $i < 10; $i++)C-style.
foreach ($xs as $x) / foreach ($map as $k => $v)The everyday loop.
while / do { … } whileStandard.
break / continue [n]Optional level — break out of N nested loops.

Types · defaults · closuresFunctions

function add(int $a, int $b): int { return $a + $b; }Typed signature.
function send(string $to, string $subject = 'hi'): voidDefault args.
send(to: 'x@y', subject: 'z')Named arguments (PHP 8+).
function sum(int ...$xs): intVariadic. Splat with sum(...$arr).
fn($x) => $x * 2Arrow function. Auto-captures by value.
function($x) use ($base) { return $base + $x; }Closure with explicit use.
strtoupper(...)Preferred First-class callable (PHP 8.1+).
$obj->method(...) / [SomeClass::class, 'method'](...)Same idea, member callables.
function fact(int $n): int => $n < 2 ? 1 : $n * fact($n - 1);Recursive arrow fn (8.4+).

OO surfaceClasses & enums

final class User { … }Preferred Closed for inheritance.
readonly class User { … }All properties readonly (PHP 8.2+).
public readonly string $idProperty-level readonly.
public function __construct(public string $name) {}Constructor promotion — declare + assign in one shot.
public static int $count = 0;Class property. Access via self::$count or User::$count.
const MAX = 100;Class constant.
interface Repo { public function find(string $id): ?User; }Interface.
abstract class Cache { abstract public function get(string $k): mixed; }Abstract class.
trait Timestamped { public ?DateTimeImmutable $createdAt = null; }Mix-in. Conflicts resolved with insteadof.
enum Status: string { case Active = 'a'; case Inactive = 'i'; }Backed enum.
Status::from('a') / Status::tryFrom('z')Construct from raw value. tryFrom returns null on miss.
#[Attribute] / #[Route('/users')]Attributes. Read at runtime via Reflection.
$x instanceof FooType test.
new class extends Base { … }Anonymous class.

Worked example

php
id, $this->name, $email);
    }
}

// Backed enum — values map to int/string
enum Role: string
{
    case Admin  = 'admin';
    case Member = 'member';
    case Guest  = 'guest';

    public function isPrivileged(): bool
    {
        return match ($this) {
            self::Admin           => true,
            self::Member, self::Guest => false,
        };
    }
}

// Interface + readonly + match expression
interface Repository
{
    public function find(string $id): ?User;
}

class InMemoryUsers implements Repository
{
    /** @var array */
    private array $store = [];

    public function upsert(User $u): void { $this->store[$u->id] = $u; }
    public function find(string $id): ?User { return $this->store[$id] ?? null; }
}

try · throw · custom errorsErrors

throw new InvalidArgumentException('…')Throw any class implementing Throwable.
throw new \RuntimeException(prev: $e)Wrap a previous exception.
try { … } catch (Foo|Bar $e) { … } finally { … }Multi-type catch (PHP 8+).
catch (\Throwable $e)Generic catch. Covers Error + Exception.
$x = expr ?? throw new E('…');Throw as expression.
json_encode($x, JSON_THROW_ON_ERROR)Make built-ins throw instead of returning false.
class NotFound extends \DomainException {}Custom hierarchy. Inherit from DomainException / RuntimeException appropriately.
set_exception_handler(fn($e) => …)Catch-all for uncaught exceptions.
error_reporting(E_ALL); ini_set('display_errors', '1');Dev visibility. Off in prod.

Dep manager · standardsComposer & PSR

composer require vendor/package:^1.0Add a dep with a version constraint.
composer require --dev phpunit/phpunitDev-only deps.
composer updateUpdate within constraints.
composer install --no-dev -oProd install. Optimized autoloader.
composer dump-autoload -oRegenerate the autoloader.
composer.json autoload.psr-4{"App\\": "src/"} — namespace → folder.
PSR-3 LoggerInterfaceLogging contract. monolog implements it.
PSR-7 / PSR-15 / PSR-17HTTP messages / middleware / factories.
PSR-11 ContainerInterfaceDI container contract.
PSR-12 / PER-CSCoding style. Most projects enforce via php-cs-fixer.

Superglobals · responsesWeb request

$_GET, $_POST, $_REQUEST, $_COOKIE, $_SESSION, $_FILES, $_SERVERSuperglobals. Available everywhere.
$_SERVER['REQUEST_METHOD'] / 'REQUEST_URI'Method + path.
getallheaders() / apache_request_headers()All request headers.
json_decode(file_get_contents('php://input'), true)Read raw JSON body.
header('Content-Type: application/json')Response header.
http_response_code(404)Set status.
echo json_encode($data)Body.
session_start() — once at the topRequired to read / write $_SESSION.
setcookie('name', $v, ['samesite' => 'Lax', 'httponly' => true])Set a cookie.
filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT)Type-safe input. Returns false on miss / mismatch.

PDO · prepared statementsDatabase

$pdo = new PDO("pgsql:host=…;dbname=…", $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION])Always set ERRMODE_EXCEPTION.
$pdo->prepare("SELECT * FROM users WHERE id = ?")Positional placeholders.
$pdo->prepare("… WHERE id = :id")Named placeholders. Easier to read.
$stmt->execute([$id])Bind + run. Never concatenate variables into SQL.
$stmt->fetch(PDO::FETCH_ASSOC)Next row as assoc array.
$stmt->fetchAll(PDO::FETCH_ASSOC)All rows.
$stmt->fetchObject(User::class)Hydrate into a class.
$pdo->beginTransaction(); … commit(); / rollBack()Transactions.
$pdo->lastInsertId()Auto-increment ID of the last insert.

Concurrent HTTP · ~35 linesEnd-to-end · Concurrent HTTP

Guzzle promises in parallel via Utils::settle. Three GitHub API calls fan out, per-call failures handled independently, output streamed.

php
 'https://api.github.com/',
    'headers'  => ['User-Agent' => 'devshelf'],
    'timeout'  => 5.0,
]);

$owners = ['php', 'symfony', 'laravel'];

// Concurrent fan-out via Guzzle promises
$promises = [];
foreach ($owners as $owner) {
    $promises[$owner] = $client->getAsync("users/{$owner}/repos?per_page=5");
}

// Wait for all; settled = no exceptions on individual failures
$results = Utils::settle($promises)->wait();

foreach ($results as $owner => $r) {
    if ($r['state'] !== 'fulfilled') {
        fwrite(STDERR, "{$owner}: " . $r['reason']->getMessage() . "\n");
        continue;
    }
    $repos = json_decode((string) $r['value']->getBody(), true, flags: JSON_THROW_ON_ERROR);
    foreach ($repos as $repo) {
        printf("%s/%s ★%d\n", $owner, $repo['name'], $repo['stargazers_count']);
    }
}

Best practiceGood to know

Turn on strict_types=1 in every file. Without it, PHP coerces '5' to 5, hiding bugs at type boundaries. Strict mode turns silent coercion into typed errors.
Mark classes final and properties readonly by default. Both fight unrelated bugs — subclass surprises and accidental mutation. Open them up only when a concrete need arises.
Run PHPStan at level 8 or Psalm in CI. The runtime is forgiving; static analysis isn’t. Most "PHP bugs" are typos and null deref that these tools catch instantly.

Common trapsWatch out for

Sort functions return bool and mutate in place. $sorted = sort($xs); assigns true to $sorted and reorders $xs. Use usort + a copy when you want a new array.
Loose equality (==) is a minefield. '0' == 'false' is true. [] == null is true. Always use === unless you have a specific reason not to.
String concatenation with + is silent type coercion. In PHP, + is numeric — "hi" + "bye" is 0. Use . for concatenation.

Go deeperSee also

PHP FAQ

What is PHP and what is it used for?

PHP is a server-side scripting language designed for web development and now widely used for backend APIs, CLI tools, and CMS platforms. It powers WordPress, Laravel, Symfony, and roughly 75% of all websites with a known server-side language. Modern PHP 8.x is type-safe, object-oriented, and performant with JIT compilation.

How does PHP handle types?

PHP is dynamically typed by default. Add declare(strict_types=1) at the top of each file to enforce type coercion rules for function arguments. Type declarations (int, string, ?float, array, MyClass) annotate function parameters and return types. Union types (int|string), intersection types (A&B), and never return type arrived in PHP 8.x.

What are PHP enums and when should I use them?

PHP 8.1 added native enums — use them instead of class constants to represent a fixed set of named values. Pure enums (enum Status) have no backing value. Backed enums (enum Status: string) have a string or int value you can use for serialisation. Enums can implement interfaces and have methods, making them much more powerful than constants.

What is Composer and why does every PHP project use it?

Composer is the dependency manager for PHP, analogous to npm for Node or pip for Python. Run composer require vendor/package to add a dependency, composer install to restore from composer.lock, and composer dump-autoload to regenerate the PSR-4 class autoloader. Every modern PHP project uses Composer to manage third-party packages and autoloading.

How do namespaces work in PHP?

Declare a namespace at the top of a PHP file with namespace App\Models. Import other namespaces with use App\Services\UserService. PSR-4 autoloading maps namespace paths to directory paths — App\Models\User maps to src/Models/User.php. Use aliases to resolve collisions: use App\Models\User as UserModel.

What are PHP attributes and how do I use them?

PHP 8.0 attributes (previously called annotations) are structured metadata placed above classes, methods, properties, or parameters using the #[Attribute] syntax. Frameworks like Symfony and Laravel use them for routing (#[Route("/api")]), validation (#[Assert\NotBlank]), and dependency injection (#[Inject]). Read them at runtime with the Reflection API.