PHP Cheatsheet

OOP and Modern PHP

Use this PHP reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Classes

final class User {
    public function __construct(
        public readonly string $email,
        private string $passwordHash,
    ) {}

    public function verify(string $password): bool {
        return password_verify($password, $this->passwordHash);
    }
}

Constructor property promotion creates and assigns properties directly from constructor parameters. readonly prevents reassignment after initialization.

Interfaces and Inheritance

interface Mailer {
    public const MAX_RETRIES = 3;   // interface constants
    public function send(string $to, string $body): void;
}

final class SmtpMailer implements Mailer {
    public function send(string $to, string $body): void {}
}

echo Mailer::MAX_RETRIES;

Prefer interfaces for dependencies. Use final when a class is not designed for extension. Interface constants are inherited by implementing classes.

Abstract Classes

abstract class Report {
    abstract protected function rows(): array;   // subclasses must implement

    public function render(): string {           // shared behavior
        return implode("\n", array_map(fn($r) => implode(',', $r), $this->rows()));
    }
}

final class SalesReport extends Report {
    protected function rows(): array { return [['q1', 100]]; }
}

Abstract classes cannot be instantiated directly. Use them when subclasses share real code, and interfaces when they only share a contract.

Static Properties and Methods

final class Counter {
    private static int $count = 0;

    public static function increment(): int {
        return ++self::$count;
    }
}

Counter::increment();
$obj::class;          // class name of an instance
static::create();     // late static binding: resolves to the called subclass

Statics belong to the class, not an instance. Prefer instance state plus dependency injection for anything you want to test or swap.

Traits

trait Timestamps {
    protected ?DateTimeImmutable $createdAt = null;

    public function touch(): void {
        $this->createdAt = new DateTimeImmutable();
    }
}

final class Post {
    use Timestamps;
}

Traits copy methods and properties into a class, which sidesteps single inheritance. Resolve name collisions with use A, B { A::save insteadof B; }.

Magic Methods

final class Money {
    public function __construct(private int $cents) {}

    public function __toString(): string {
        return sprintf('$%.2f', $this->cents / 100);
    }

    public function __get(string $name): mixed {
        return $this->data[$name] ?? null;   // called for undefined properties
    }
}

echo new Money(1999);   // $19.99

Common magic methods: __toString, __get/__set (undefined property access), __call/__callStatic (undefined methods), __invoke (call the object like a function), __clone. On PHP 8.4+, prefer property hooks (public string $name { get => ...; }) over __get for known properties.

Attributes

#[Attribute(Attribute::TARGET_METHOD)]
final class Route {
    public function __construct(public string $path, public array $methods = ['GET']) {}
}

final class UserController extends Controller {
    #[Route('/users/{id}', methods: ['GET'])]
    public function show(int $id): void {}

    #[\Override]                   // PHP 8.3+: errors unless a parent declares this method
    protected function middleware(): array { return []; }
}

$attrs = (new ReflectionMethod(UserController::class, 'show'))->getAttributes(Route::class);
$route = $attrs[0]->newInstance();

Attributes (#[...]) attach structured metadata read via reflection. Frameworks use them for routing, DI wiring, validation, and ORM mapping.

Enums

enum Role: string {
    case Student = 'student';
    case Admin = 'admin';

    public function label(): string {
        return ucfirst($this->value);
    }
}

$role = Role::Student;
$role->value;                 // student
Role::from('admin');          // throws on unknown value
Role::tryFrom('nope');        // null on unknown value

Backed enums are safer than passing raw strings around. Enums may hold methods, constants, and interfaces, but no mutable state.

Exceptions

if ($id <= 0) {
    throw new InvalidArgumentException('id must be positive');
}

try {
    run();
} catch (PDOException | JsonException $e) {
    error_log($e->getMessage());
} catch (Throwable $e) {
    error_log($e->getMessage());
} finally {
    cleanup();
}

Catch Throwable at application boundaries; throw specific exception types inside domain code.

Namespaces and Autoloading

namespace App\Billing;

use App\Database\Connection;
use App\Database\{Migrator, Seeder};
use function App\Support\slugify;

Composer autoloading maps namespaces to directories so you do not hand-write require lines everywhere.