Toolmingo
Guides23 min read

50 PHP Interview Questions (With Answers)

Top PHP interview questions with clear answers and code examples — covering OOP, PHP 8 features, arrays, security, PDO, Composer, and modern PHP patterns.

PHP powers over 75% of websites with a known server-side language. Interviews test your understanding of the language core, OOP, security, PHP 8 features, and modern tooling. This guide covers the 50 most common questions — with concise answers and code examples.

Quick reference

Topic Most asked questions
Types & Variables == vs ===, type juggling, casting
OOP Abstract vs interface, traits, visibility
PHP 8+ Match expression, named args, enums, fibers
Arrays Functions, sorting, array_map vs array_walk
Strings Manipulation, regex, multibyte functions
Error handling Exceptions, error levels, try/catch/finally
Database PDO, prepared statements, SQL injection
Security XSS, CSRF, password hashing, filter_input
Composer & PSR Autoloading, PSR-4, PSR-12
Patterns Singleton, Factory, Repository, DI

Types & Variables

1. What is the difference between == and === in PHP?

== performs loose comparison with type juggling; === checks value and type.

var_dump(0 == "foo");    // true  (PHP 7) / false (PHP 8!)
var_dump(0 === "foo");   // false

var_dump("1" == true);   // true
var_dump("1" === true);  // false

var_dump(null == false); // true
var_dump(null === false);// false

PHP 8 change: 0 == "foo" now returns false (the string is cast to 0 only when it looks numeric).

Use === by default — it is unambiguous.


2. What are PHP's scalar types?

Type Values Notes
bool true, false Case-insensitive
int −2^63 to 2^63−1 Platform dependent (64-bit common)
float IEEE 754 double Use bcmath for money
string Sequence of bytes Not natively Unicode-aware

Compound types: array, object, callable, iterable. Special types: null, void, never (return type only).


3. What is type juggling and how do you avoid it?

PHP automatically converts types when an operation requires it:

echo "5" + 3;   // 8 (string cast to int)
echo "5 dogs" + 1; // 6 (leading numeric prefix)

Avoid it by:

  1. Using strict comparison (===)
  2. Enabling strict mode: declare(strict_types=1); at the top of the file
  3. Using typed properties and return types
declare(strict_types=1);

function add(int $a, int $b): int {
    return $a + $b;
}

add("5", 3); // TypeError in strict mode

4. What are nullable types and union types?

// Nullable type (PHP 7.1+) — value or null
function findUser(?int $id): ?User { ... }

// Union types (PHP 8.0+)
function processInput(int|string $value): void { ... }

// PHP 8.1: intersection types
function render(Countable&Stringable $obj): string { ... }

// PHP 8.2: true, false, null as standalone types
function isEnabled(): true { return true; }

5. What is the difference between isset(), empty(), and is_null()?

Expression null 0 "" "0" [] false
isset($x) false true true true true true
empty($x) true true true true true true
is_null($x) true false false false false false

isset() also returns false if the variable is not declared — unlike is_null(), which throws a notice on undefined variables.


OOP

6. What is the difference between abstract class and interface?

Feature Abstract class Interface
Methods Can have implemented methods Only abstract (until PHP 8 + default methods via traits)
Properties Can have properties Cannot have properties
Constructor Yes No
Inheritance Single (extends) Multiple (implements)
Constants Yes Yes
Use when Shared base behaviour Contract / capability
abstract class Animal {
    protected string $name;
    abstract public function speak(): string;

    public function introduce(): string {
        return "I'm {$this->name}: " . $this->speak();
    }
}

interface Serializable {
    public function serialize(): string;
}

class Dog extends Animal implements Serializable {
    public function __construct(string $name) {
        $this->name = $name;
    }

    public function speak(): string { return "Woof!"; }
    public function serialize(): string { return json_encode(['name' => $this->name]); }
}

7. What are traits and when do you use them?

A trait is a mechanism for code reuse in single-inheritance languages. It is copied into the class at compile time.

trait Timestamps {
    private \DateTimeImmutable $createdAt;
    private \DateTimeImmutable $updatedAt;

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

    public function getCreatedAt(): \DateTimeImmutable {
        return $this->createdAt;
    }
}

class Post {
    use Timestamps;

    public function __construct(private string $title) {
        $this->createdAt = new \DateTimeImmutable();
        $this->updatedAt = new \DateTimeImmutable();
    }
}

Use traits for horizontal reuse — shared behaviour that doesn't fit in an inheritance hierarchy (e.g., logging, timestamps, soft deletes).

Conflict resolution:

class Foo {
    use TraitA, TraitB {
        TraitA::hello insteadof TraitB;
        TraitB::hello as helloB;
    }
}

8. Explain PHP visibility modifiers.

Modifier Same class Subclass Outside
public
protected
private

PHP 8.1 added readonly properties (set once in constructor, then immutable):

class Point {
    public function __construct(
        public readonly float $x,
        public readonly float $y,
    ) {}
}

$p = new Point(1.0, 2.0);
$p->x = 3.0; // Error: Cannot modify readonly property

9. What are magic methods? Name five important ones.

Method When called
__construct() Object instantiation
__destruct() Object destruction / end of scope
__get($name) Reading inaccessible/undefined property
__set($name, $value) Writing inaccessible property
__toString() Object used as string
__invoke() Object called as function
__clone() Object is cloned
__call($name, $args) Calling inaccessible method
__callStatic($name, $args) Calling inaccessible static method
__debugInfo() var_dump() output
class Money {
    public function __construct(
        private int $amount,
        private string $currency
    ) {}

    public function __toString(): string {
        return "{$this->amount} {$this->currency}";
    }

    public function __invoke(int $factor): static {
        return new static($this->amount * $factor, $this->currency);
    }
}

$price = new Money(100, 'EUR');
echo $price;        // "100 EUR"
$double = $price(2);
echo $double;       // "200 EUR"

10. What is late static binding? How does it differ from self?

  • self:: refers to the class where the method is defined.
  • static:: refers to the class used at runtime (late static binding, PHP 5.3+).
class Base {
    public static function create(): static {
        return new static(); // Late static binding
    }

    public static function className(): string {
        return static::class; // Runtime class name
    }
}

class Child extends Base {}

$obj = Child::create();  // Returns Child instance (not Base)
echo Child::className(); // "Child"

PHP 8+ Features

11. What is the match expression?

match is a strict, expression-based replacement for switch:

// switch (loose ==, needs break, no return value)
switch ($status) {
    case 1:
        $label = 'Active';
        break;
    case 2:
        $label = 'Inactive';
        break;
    default:
        $label = 'Unknown';
}

// match (strict ===, expression, exhaustive)
$label = match($status) {
    1 => 'Active',
    2, 3 => 'Inactive',  // Multiple conditions
    default => throw new \InvalidArgumentException("Unknown status"),
};

match throws UnhandledMatchError if no arm matches and there is no default.


12. What are named arguments?

Named arguments let you pass values by parameter name, skipping optional parameters:

// Before PHP 8 — you had to pass every preceding arg
array_slice($array, 0, null, true); // preserve_keys = true

// PHP 8 — skip to the parameter you need
array_slice($array, 0, preserve_keys: true);

// Self-documenting
$result = implode(separator: ', ', array: $items);

Cannot be used with variadic ...$args.


13. What are enums (PHP 8.1)?

Enums are first-class types instead of class constants or integer mappings:

// Pure enum (no value)
enum Status {
    case Active;
    case Inactive;
    case Pending;
}

// Backed enum (int or string backing value)
enum Color: string {
    case Red   = 'red';
    case Green = 'green';
    case Blue  = 'blue';

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

// Usage
$status = Status::Active;
$color  = Color::from('red');       // Color::Red
$color2 = Color::tryFrom('purple'); // null (not an exception)

echo $color->label(); // "Red"

// Enums in match
$hex = match($color) {
    Color::Red   => '#ff0000',
    Color::Green => '#00ff00',
    Color::Blue  => '#0000ff',
};

14. What is the nullsafe operator (?->)?

Chains method/property access and short-circuits on null:

// Before PHP 8 — nested null checks
$city = null;
if ($user !== null) {
    $address = $user->getAddress();
    if ($address !== null) {
        $city = $address->getCity();
    }
}

// PHP 8 nullsafe operator
$city = $user?->getAddress()?->getCity();

Returns null as soon as any link in the chain is null.


15. What are Fibers (PHP 8.1)?

Fibers are lightweight cooperative coroutines — stackful, interruptible functions:

$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('first');  // Yield control, receive value back
    echo "Resumed with: {$value}\n";
});

$yielded = $fiber->start();           // Start fiber, run to first suspend
echo "Fiber yielded: {$yielded}\n";   // "Fiber yielded: first"
$fiber->resume('hello');              // Resume, pass value in
// "Resumed with: hello"

Fibers power async frameworks like ReactPHP and Amp without callback hell.


Arrays

16. What is the difference between array_map() and array_walk()?

array_map() array_walk()
Return value New array true/false (modifies in-place)
Keys Preserves (string), resets (int) Preserves
Callback args (value) (&value, key)
Multiple arrays Yes No
$prices = [100, 200, 300];

// array_map — returns new array
$with_tax = array_map(fn($p) => $p * 1.2, $prices);

// array_walk — mutates in place
array_walk($prices, function (&$price, $key) {
    $price = "$key: {$price}€";
});

17. How do you sort an array while preserving keys?

Function Sorts by Preserves keys
sort() Values ascending No
rsort() Values descending No
asort() Values ascending Yes
arsort() Values descending Yes
ksort() Keys ascending Yes
krsort() Keys descending Yes
usort() Custom callback No
uasort() Custom callback Yes
uksort() Custom (keys) Yes
$scores = ['Alice' => 90, 'Bob' => 75, 'Carol' => 85];
arsort($scores); // Alice=>90, Carol=>85, Bob=>75 (keys preserved)

// Custom object sort
usort($users, fn($a, $b) => $a->age <=> $b->age);

18. What does the spread operator (...) do with arrays?

// Unpack into function call
$args = [1, 2, 3];
echo array_sum(...$args);  // Doesn't work this way; used in function defs

// Merge arrays (PHP 7.4+)
$a = [1, 2, 3];
$b = [4, 5, 6];
$merged = [...$a, ...$b]; // [1, 2, 3, 4, 5, 6]

// String keys (PHP 8.1+)
$defaults = ['color' => 'red', 'size' => 'M'];
$overrides = ['size' => 'L'];
$final = [...$defaults, ...$overrides]; // ['color' => 'red', 'size' => 'L']

19. What is array_reduce() and when do you use it?

array_reduce() folds an array into a single value using a callback:

$orders = [
    ['amount' => 100, 'tax' => 20],
    ['amount' => 200, 'tax' => 40],
    ['amount' => 50,  'tax' => 10],
];

$total = array_reduce($orders, function (int $carry, array $order): int {
    return $carry + $order['amount'] + $order['tax'];
}, 0);

// $total = 420

Strings

20. How do PHP's string delimiters differ?

Syntax Variable interpolation Escape sequences
Single quotes '' No \\ and \' only
Double quotes "" Yes Full (\n, \t, \u{...})
Heredoc <<<EOT Yes Full
Nowdoc <<<'EOT' No None
$name = "World";
echo 'Hello $name';       // Hello $name
echo "Hello $name";       // Hello World
echo "Hello {$name}!";    // Hello World! (complex expressions)

$sql = <<<EOT
    SELECT *
    FROM users
    WHERE name = '$name'
EOT;

21. What are multibyte string functions and why do you need them?

PHP's standard strlen(), substr(), strtolower() operate on bytes, not characters. For UTF-8 text, one character can be 1–4 bytes.

$str = "café";
echo strlen($str);     // 5 (bytes, not 4!)
echo mb_strlen($str);  // 4 (characters)

echo strtolower("İ");          // wrong for Turkish
echo mb_strtolower("İ", 'UTF-8'); // correct

echo substr("café", 3);        // may cut in mid-character
echo mb_substr("café", 3);     // "é" — correct

Always use mb_* functions for user-facing strings. Set mbstring.internal_encoding = UTF-8 in php.ini.


22. How do you use regular expressions in PHP?

// preg_match — find first match
if (preg_match('/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i', $email)) {
    echo "Valid email";
}

// preg_match_all — find all matches
$html = '<a href="foo.html">Foo</a> <a href="bar.html">Bar</a>';
preg_match_all('/<a href="([^"]+)">/', $html, $matches);
// $matches[1] = ['foo.html', 'bar.html']

// preg_replace
$clean = preg_replace('/\s+/', ' ', $text);

// preg_split
$parts = preg_split('/[\s,;]+/', "one, two;  three");

// preg_replace_callback
$result = preg_replace_callback('/\d+/', function ($m) {
    return $m[0] * 2;
}, "I have 3 cats and 5 dogs"); // "I have 6 cats and 10 dogs"

Error Handling

23. What are the PHP error levels?

Constant Value Description
E_ERROR 1 Fatal run-time error (stops execution)
E_WARNING 2 Run-time warning (does not stop)
E_NOTICE 8 Informational (undefined variable)
E_DEPRECATED 8192 Deprecated feature
E_ALL 32767 All errors

In php.ini:

  • Development: error_reporting = E_ALL
  • Production: error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT + display_errors = Off + log_errors = On

24. How does exception handling work in PHP?

class NotFoundException extends \RuntimeException {}
class DatabaseException extends \RuntimeException {}

function findUser(int $id): array {
    try {
        $user = $db->query("SELECT * FROM users WHERE id = ?", [$id]);
        if (!$user) {
            throw new NotFoundException("User {$id} not found", 404);
        }
        return $user;
    } catch (DatabaseException $e) {
        logger()->error('DB error', ['exception' => $e]);
        throw new \RuntimeException('Database unavailable', 503, $e); // Chain exceptions
    } finally {
        $db->close(); // Always runs
    }
}

// Multiple catch (PHP 8: catch without variable)
try {
    findUser(99);
} catch (NotFoundException | \InvalidArgumentException $e) {
    http_response_code(404);
    echo $e->getMessage();
} catch (\Throwable $e) { // Catches Error and Exception
    http_response_code(500);
}

25. What is the difference between Exception and Error?

Since PHP 7, both implement \Throwable:

Exception Error
Use for Application / business logic PHP engine errors
Examples InvalidArgumentException, RuntimeException TypeError, ParseError, ArithmeticError
Catchable Yes Yes (with catch(\Error) or catch(\Throwable))
// Catching both
try {
    riskyOperation();
} catch (\Exception $e) {
    // Application-level
} catch (\Error $e) {
    // Engine-level (TypeError, etc.)
}

// Catch everything
} catch (\Throwable $e) { ... }

Database & Security

26. What is PDO and why use it over mysqli?

PDO (PHP Data Objects) is a database abstraction layer supporting 12 drivers.

Feature PDO mysqli
Database support 12+ MySQL only
API style OOP + procedural OOP + procedural
Named placeholders Yes (:name) No
Prepared statements Yes Yes
Transactions Yes Yes
// PDO connection
$pdo = new \PDO(
    'mysql:host=localhost;dbname=mydb;charset=utf8mb4',
    'user',
    'password',
    [
        \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
        \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
        \PDO::ATTR_EMULATE_PREPARES   => false,
    ]
);

// Prepared statement (prevents SQL injection)
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND active = :active');
$stmt->execute([':email' => $email, ':active' => 1]);
$user = $stmt->fetch();

27. How do you prevent SQL injection?

Never interpolate user input into queries. Always use prepared statements:

// VULNERABLE
$sql = "SELECT * FROM users WHERE name = '{$_GET['name']}'";

// SAFE — PDO named placeholder
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');
$stmt->execute([':name' => $_GET['name']]);

// SAFE — positional placeholder
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$_GET['id']]);

Additional measures:

  • Whitelist column/table names if they come from user input
  • Use LIMIT to reduce data exposure
  • Apply least-privilege DB user permissions

28. How do you prevent XSS (Cross-Site Scripting)?

Escape output according to context:

// HTML context — htmlspecialchars
echo htmlspecialchars($userInput, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

// URL context
echo urlencode($userInput);

// JavaScript context — json_encode is safe
$json = json_encode($userInput, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
echo "<script>var data = {$json};</script>";

Content Security Policy (HTTP header) as defense in depth:

Content-Security-Policy: default-src 'self'; script-src 'self'

29. How do you hash passwords correctly in PHP?

// Hash (uses bcrypt by default — strong, salted, adaptive)
$hash = password_hash($plainPassword, PASSWORD_BCRYPT, ['cost' => 12]);

// Or use the recommended default (currently bcrypt, future-proof)
$hash = password_hash($plainPassword, PASSWORD_DEFAULT);

// Verify — NEVER compare hashes with == or ===
if (password_verify($plainPassword, $storedHash)) {
    // Authenticated

    // Rehash if algorithm or cost changed
    if (password_needs_rehash($storedHash, PASSWORD_DEFAULT)) {
        $newHash = password_hash($plainPassword, PASSWORD_DEFAULT);
        // Store $newHash
    }
}

Never use: md5(), sha1(), sha256() for passwords — too fast, no salt by default.


30. How do you handle CSRF protection?

// Generate token (store in session)
function csrfToken(): string {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

// Embed in form
echo '<input type="hidden" name="csrf_token" value="' . csrfToken() . '">';

// Validate on POST
function validateCsrf(): void {
    $token = $_POST['csrf_token'] ?? '';
    if (!hash_equals($_SESSION['csrf_token'] ?? '', $token)) {
        http_response_code(403);
        die('CSRF validation failed');
    }
}

Use hash_equals() to prevent timing attacks.


Composer & PSR Standards

31. What is Composer and what does composer.lock do?

Composer is PHP's dependency manager. composer.lock pins exact versions of all packages (including transitive dependencies) for reproducible installs.

composer require vendor/package          # Add dependency
composer require --dev vendor/package    # Dev dependency
composer install                         # Install from composer.lock (CI/prod)
composer update                          # Update within constraints + rewrite lock
composer dump-autoload                   # Regenerate autoloader

Always commit composer.lock for applications. Libraries should gitignore it.


32. What is PSR-4 autoloading?

PSR-4 maps namespace prefixes to directory paths:

// composer.json
{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

App\Controllers\UserControllersrc/Controllers/UserController.php

Rules:

  • One class per file
  • File name == class name (case-sensitive on Linux)
  • Namespace mirrors directory structure

33. What are the key PSR standards?

PSR Topic
PSR-1 Basic coding standard (opening tags, class names)
PSR-2 / PSR-12 Coding style (indentation, braces, line length)
PSR-3 Logger interface
PSR-4 Autoloading
PSR-6 Caching interface
PSR-7 HTTP message interface
PSR-11 Container interface (DI)
PSR-14 Event dispatcher
PSR-15 HTTP handlers (middleware)
PSR-17 HTTP factories
PSR-18 HTTP client

Design Patterns

34. Implement the Singleton pattern in PHP.

final class Database {
    private static ?self $instance = null;
    private \PDO $connection;

    private function __construct() {
        $this->connection = new \PDO(/* ... */);
    }

    // Prevent cloning
    private function __clone() {}

    public static function getInstance(): static {
        if (static::$instance === null) {
            static::$instance = new static();
        }
        return static::$instance;
    }

    public function getConnection(): \PDO {
        return $this->connection;
    }
}

$db = Database::getInstance();

In modern PHP, prefer Dependency Injection over Singleton — it makes testing easier.


35. What is the Repository pattern?

Separates data access from business logic:

interface UserRepository {
    public function find(int $id): ?User;
    public function findAll(): array;
    public function save(User $user): void;
    public function delete(int $id): void;
}

class PdoUserRepository implements UserRepository {
    public function __construct(private \PDO $pdo) {}

    public function find(int $id): ?User {
        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$id]);
        $row = $stmt->fetch();
        return $row ? User::fromArray($row) : null;
    }
    // ...
}

// Controller depends on the interface, not the concrete class
class UserController {
    public function __construct(private UserRepository $users) {}

    public function show(int $id): array {
        $user = $this->users->find($id);
        if (!$user) throw new NotFoundException();
        return $user->toArray();
    }
}

36. What is Dependency Injection?

DI passes dependencies to a class rather than the class creating them:

// BAD — tight coupling
class OrderService {
    private EmailService $mailer;
    public function __construct() {
        $this->mailer = new EmailService(); // hard to test, hard to swap
    }
}

// GOOD — constructor injection
class OrderService {
    public function __construct(
        private readonly EmailServiceInterface $mailer,
        private readonly OrderRepository $orders,
    ) {}
}

// Wire up with a DI container (e.g., PHP-DI, Pimple)
$container->bind(EmailServiceInterface::class, SmtpEmailService::class);
$service = $container->get(OrderService::class);

Performance

37. What is OPcache and how does it work?

OPcache stores the compiled bytecode of PHP scripts in shared memory, eliminating repeated parsing and compilation.

; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60      ; seconds (0 = always revalidate in dev)
opcache.validate_timestamps=0   ; disable for maximum performance in prod
# Check OPcache status
php -r "var_dump(opcache_get_status());"

# Invalidate a single file after deploy
opcache_invalidate('/path/to/file.php', true);

38. What are some PHP performance tips?

Tip Why
Enable OPcache Eliminates repeated compilation
Use echo not print print is slightly slower (returns value)
Avoid @ error suppression Slow — use proper checks instead
Use isset() instead of array_key_exists() for nulls Faster
Prefer str_contains() over strpos() !== false PHP 8, clearer + slightly faster
Use generators for large datasets Low memory — values on demand
Cache DB queries APCu, Redis, Memcached
Profile with Xdebug/Blackfire Find real bottlenecks

Modern PHP Patterns

39. What are generators and when are they useful?

A generator is a function that yields values on demand without building a full array in memory:

// Memory efficient CSV reader
function readCsv(string $path): \Generator {
    $fh = fopen($path, 'r');
    while (($row = fgetcsv($fh)) !== false) {
        yield $row;
    }
    fclose($fh);
}

// Process a 1 GB CSV with constant memory
foreach (readCsv('big.csv') as [$id, $name, $email]) {
    processRow($id, $name, $email);
}

// yield from — delegate to another generator
function merge(\Generator ...$gens): \Generator {
    foreach ($gens as $gen) {
        yield from $gen;
    }
}

40. What are first-class callables (PHP 8.1)?

// Before PHP 8.1 — anonymous function wrapper
$fn = fn($x) => strlen($x);
$lengths = array_map(fn($s) => strlen($s), $strings);

// PHP 8.1 — first-class callable syntax
$fn = strlen(...);
$lengths = array_map(strlen(...), $strings);

// Works with methods too
$trimmed = array_map($str->trim(...), $strings);
$users   = array_map(User::fromArray(...), $rows);

41. What are readonly classes (PHP 8.2)?

All properties of a readonly class are implicitly readonly:

readonly class Point {
    public function __construct(
        public float $x,
        public float $y,
        public float $z = 0.0,
    ) {}
}

$p = new Point(1.0, 2.0);
$p->x = 3.0; // Error: readonly

Ideal for value objects and DTOs.


42. What are PHP attributes (PHP 8.0)?

Attributes are structured metadata (replacing docblock annotations):

#[Attribute]
class Route {
    public function __construct(
        public string $path,
        public string $method = 'GET',
    ) {}
}

class UserController {
    #[Route('/users', 'GET')]
    public function index(): array { ... }

    #[Route('/users/{id}', 'GET')]
    public function show(int $id): array { ... }
}

// Read attributes via reflection
$ref = new \ReflectionMethod(UserController::class, 'index');
$attrs = $ref->getAttributes(Route::class);
$route = $attrs[0]->newInstance();
echo $route->path; // '/users'

Miscellaneous

43. What is the difference between require, include, require_once, and include_once?

On failure Allows re-inclusion
include Warning (continues) Yes
require Fatal error (stops) Yes
include_once Warning (continues) No
require_once Fatal error (stops) No

Use require for files essential to the application, include for optional templates. In practice, Composer autoloading makes manual include/require rare.


44. What is output buffering?

Output buffering captures output instead of sending it immediately to the browser:

ob_start();
include 'template.php';
$html = ob_get_clean(); // Capture and stop buffering

// Useful for: capturing template output, gzip compression, headers after output

45. What does list() / [...] destructuring do?

// list() — positional destructuring
[$first, $second, $third] = [1, 2, 3];

// Skip elements
[, $second] = [1, 2, 3];

// Nested
[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];

// With string keys (PHP 7.1+)
['name' => $name, 'age' => $age] = ['name' => 'Alice', 'age' => 30];

// In foreach
$points = [[1, 2], [3, 4], [5, 6]];
foreach ($points as [$x, $y]) {
    echo "{$x}, {$y}\n";
}

46. How does PHP handle references (&)?

$a = 1;
$b = &$a; // $b references the same memory as $a
$b = 2;
echo $a;  // 2

// Function reference parameters
function increment(int &$value): void {
    $value++;
}
$x = 5;
increment($x);
echo $x; // 6

// foreach by reference
$numbers = [1, 2, 3];
foreach ($numbers as &$num) {
    $num *= 2;
}
unset($num); // IMPORTANT: unset reference after loop to avoid bugs

47. What is declare(strict_types=1) and where must it appear?

<?php
declare(strict_types=1); // Must be the FIRST statement in the file

function add(int $a, int $b): int {
    return $a + $b;
}

add(1.5, 2); // TypeError: must be int, float given

Without strict_types, PHP coerces 1.51. This only affects the file containing the declaration (not called functions from other files).


48. What are the PHP superglobals?

Variable Content
$_GET URL query parameters
$_POST POST body (form data)
$_COOKIE Cookies
$_SESSION Session data
$_SERVER Server and request info
$_FILES Uploaded files
$_REQUEST $_GET + $_POST + $_COOKIE (avoid)
$_ENV Environment variables
$GLOBALS All global variables

Always filter/validate superglobal values:

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === false || $id === null) {
    http_response_code(400);
    die('Invalid ID');
}

49. What are arrow functions?

Arrow functions (PHP 7.4+) are single-expression closures that capture outer variables automatically:

$multiplier = 3;

// Regular closure — must use `use`
$fn = function (int $x) use ($multiplier): int {
    return $x * $multiplier;
};

// Arrow function — captures automatically
$fn = fn(int $x): int => $x * $multiplier;

// Nested arrow functions
$add = fn($a) => fn($b) => $a + $b;
$add5 = $add(5);
echo $add5(3); // 8

Limitation: single expression only (no multi-line body).


50. What are common PHP anti-patterns to avoid?

Anti-pattern Problem Better approach
mysql_* functions Removed in PHP 7 Use PDO or mysqli
@ error suppression Hides bugs, slows code Use proper null checks
global $var Hidden coupling Dependency injection
extract($_POST) Pollutes scope, security risk Access keys explicitly
Using == for security checks Type juggling bypasses Use === or hash_equals()
Storing plaintext passwords Critical security issue password_hash()
Not escaping output XSS vulnerability htmlspecialchars()
Selecting SELECT * Over-fetching, fragile Select only needed columns

Common mistakes

Mistake Correct approach
echo vs print — thinking print is faster echo is marginally faster; use it
Comparing with == null instead of === null Always use strict comparison
Using count() in a loop condition Cache the count: $n = count($arr)
array_push($arr, $val) for single element $arr[] = $val is faster
Not closing DB connections in long-running scripts Use $pdo = null or explicit disconnect
Using file_get_contents() for large files Use streaming (fopen, generators)
Trusting $_SERVER['HTTP_HOST'] without validation Can be spoofed; whitelist expected hosts
Not setting charset=utf8mb4 in PDO DSN Emoji and some CJK chars silently truncated

PHP vs other languages

Feature PHP Python Node.js
Paradigm Multi-paradigm Multi-paradigm Event-driven
Typing Dynamic + optional strict Dynamic + type hints Dynamic
Concurrency Multi-process (FPM) GIL / asyncio Single-thread async
Package manager Composer pip npm
Template engine Blade, Twig, native Jinja2, native Pug, Handlebars
Primary use Web (dominant) ML, data, web Web, APIs, tooling

FAQ

Q: What is the difference between echo and print? echo outputs one or more strings, accepts multiple comma-separated arguments, and has no return value. print outputs a single string and returns 1. In practice always use echo.

Q: How does PHP's garbage collector work? PHP uses reference counting as the primary mechanism. When a variable's reference count drops to zero, memory is freed immediately. A cyclic garbage collector (enabled by default since PHP 5.3) handles circular references using the tri-color mark-and-sweep algorithm. You can trigger it manually with gc_collect_cycles().

Q: What is the difference between static and self for properties? self::$property always refers to the class where the code is written. static::$property uses late static binding — it resolves to the class that called the method at runtime, enabling polymorphic static behaviour.

Q: How does session management work in PHP? session_start() creates or resumes a session. A session ID is stored in a cookie (PHPSESSID by default); session data is stored server-side (filesystem by default, configurable to Redis/DB). Regenerate the session ID after login with session_regenerate_id(true) to prevent session fixation attacks.

Q: What is the spaceship operator (<=>)? Returns -1, 0, or 1 for less than, equal, or greater than. Useful for usort callbacks: usort($arr, fn($a, $b) => $a <=> $b).

Q: When should I use abstract class vs interface? Use an interface when you want to define a contract (what a class can do) without any implementation — especially when multiple unrelated classes should share the contract. Use an abstract class when you want to share implementation code (concrete methods) among related classes that share an "is-a" relationship.

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools