Top 60 PHP Interview Questions (2026)

The 60 PHP questions interviewers actually ask, with direct answers, runnable code, and what the interviewer is listening for. Grouped for freshers, intermediate, and experienced rounds.

60 questions with answers

What Is PHP?

Key Takeaways

  • PHP is a server-side scripting language built for the web, embedded directly in HTML and run by an interpreter on the server.
  • It powers a large share of the web through platforms like WordPress, Laravel, and Symfony, and pairs naturally with MySQL and other databases.
  • Interviews test the type system quirks (loose vs strict comparison), arrays, OOP, and request-lifecycle thinking, not just syntax recall.
  • This page is a question bank: work your tier first, read one tier up, and say answers out loud because delivery gets evaluated too.

PHP is a server-side scripting language created by Rasmus Lerdorf in 1994 and designed for building dynamic web pages. Code lives inside <?php ?> tags, can be mixed straight into HTML, and runs through an interpreter on the server, which returns plain HTML to the browser. It's dynamically typed, supports procedural and object-oriented styles, and ships with thousands of built-in functions for strings, arrays, dates, and database access. In interviews, PHP questions probe the type system's loose-comparison rules, PHP's array (an ordered map that doubles as list and dictionary), the object model, and how a request flows from web server to script to response. This page collects the 60 questions that come up most, each with a direct answer and runnable code. For fundamentals, the official PHP manual from The PHP Group is the canonical reference; increasingly the first PHP round runs as a live AI coding interview, so pair this bank with our AI interview preparation guides for the format side.

60Questions with answers on this page
3Difficulty tiers: freshers, intermediate, experienced
24Runnable code snippets you can practice from
45-60 minTypical length of a PHP technical round

Watch: PHP Tutorial for Beginners - Full Course | OVER 7 HOURS!

Video: PHP Tutorial for Beginners - Full Course | OVER 7 HOURS! (Envato Tuts+, YouTube)

Test yourself and earn a certificate

10 quick questions. Score 70%+ to download your PHP certificate.

Jump to quiz

All Questions on This Page

60 questions
PHP Interview Questions for Freshers
  1. 1. What is PHP and what is it used for?
  2. 2. What is the difference between echo and print?
  3. 3. How do you declare variables in PHP, and what are the naming rules?
  4. 4. What is the difference between single and double quoted strings?
  5. 5. What is a PHP array and what kinds are there?
  6. 6. What is the difference between == and === in PHP?
  7. 7. What is the difference between include and require?
  8. 8. What are superglobals in PHP?
  9. 9. What is the difference between GET and POST requests?
  10. 10. How do you concatenate strings in PHP?
  11. 11. What is the difference between isset(), empty(), and is_null()?
  12. 12. How do you define a function in PHP, and how are default and typed parameters written?
  13. 13. How do you define constants in PHP?
  14. 14. What are the ternary and null-coalescing operators?
  15. 15. What is type juggling in PHP?
  16. 16. Which array functions should every PHP developer know?
  17. 17. How does the foreach loop work?
  18. 18. What is the difference between sessions and cookies?
  19. 19. How do you embed PHP inside HTML?
  20. 20. How do you write comments in PHP?
  21. 21. What is the difference between an error and an exception in PHP?
  22. 22. What does htmlspecialchars() do and why does it matter?
PHP Intermediate Interview Questions
  1. 23. How does PHP implement object-oriented programming?
  2. 24. What do public, protected, and private mean?
  3. 25. What is the difference between an abstract class and an interface?
  4. 26. What are traits and when would you use them?
  5. 27. What are static properties and methods?
  6. 28. What are magic methods in PHP?
  7. 29. What is PDO and how does it compare to mysqli?
  8. 30. What are prepared statements and why do they prevent SQL injection?
  9. 31. Beyond SQL injection, what web security issues should a PHP developer guard against?
  10. 32. How should you store passwords in PHP?
  11. 33. What are namespaces and how does autoloading work?
  12. 34. What is Composer and what problem does it solve?
  13. 35. What type declarations does modern PHP support?
  14. 36. What is the match expression and how does it differ from switch?
  15. 37. What are arrow functions and how do they differ from closures?
  16. 38. What are generators in PHP?
  17. 39. How does passing by value versus by reference work in PHP?
  18. 40. What are variadic functions and the spread operator?
  19. 41. How do you encode and decode JSON in PHP?
  20. 42. How do you work with dates and times in PHP?
PHP Interview Questions for Experienced Developers
  1. 43. Walk through what happens when a PHP request is served.
  2. 44. What is OPcache and why does it matter for performance?
  3. 45. How does PHP manage memory and garbage collection?
  4. 46. What are PSR standards and which ones matter?
  5. 47. What is dependency injection and how is it used in PHP frameworks?
  6. 48. What did PHP 8.1 and 8.2 add that changed how you model data?
  7. 49. What is late static binding?
  8. 50. How do you resolve method conflicts when combining traits?
  9. 51. How do you build immutable value objects in PHP?
  10. 52. What is the N+1 query problem and how do you fix it in PHP?
  11. 53. How do you add caching to a PHP application?
  12. 54. Can PHP do asynchronous or concurrent work?
  13. 55. How do you test a PHP application?
  14. 56. How do you handle errors and logging in a production PHP service?
  15. 57. How does object copying work, and what does __clone do?
  16. 58. What exactly does declare(strict_types=1) change, and where does it apply?
  17. 59. Design question: how would you structure a REST API in PHP?
  18. 60. How do you scale a PHP application under growing traffic?

PHP Interview Questions for Freshers

Freshers22 questions

The fundamentals every entry-level round checks. If any answer here surprises you, that's your study list.

Q1. What is PHP and what is it used for?

PHP is a server-side scripting language made for the web. Code sits inside <?php ?> tags, runs on the server, and produces HTML that the browser receives. The name stands for PHP: Hypertext Preprocessor, a recursive acronym.

It's used to build dynamic websites and web apps: handling forms, talking to databases, managing sessions and authentication, and generating pages. It backs content platforms like WordPress and frameworks like Laravel and Symfony.

Key point: A one-line definition plus a concrete example (WordPress, form handling) beats a memorized feature list. Interviewers open with this to hear how you organize an answer.

Watch a deeper explanation

Video: PHP Full Course for free 🐘 (Bro Code, YouTube)

Q2. What is the difference between echo and print?

Both send output to the browser, and in everyday code they look interchangeable. The differences are small: echo can take multiple comma-separated arguments and returns nothing, while print takes a single argument and returns the integer 1, which means print can sit inside a larger expression where echo can't.

In practice echo is used almost everywhere because it's marginally faster and the multi-argument form is handy. The return value of print is a trivia point that rarely matters day to day.

php
echo "Hello", " ", "world";   // multiple args, no return

$ok = print "done";           // returns 1
// $ok is now 1

Q3. How do you declare variables in PHP, and what are the naming rules?

Every variable starts with a dollar sign, and you assign with =. There's no separate type declaration; the type comes from the value, so $count = 5 is an int and $name = "Asha" is a string.

Names are case-sensitive, must a letter or underscore after the dollar sign, and can't a digit comes first comes first. PHP is loosely typed, so the same variable can later hold a value of a different type.

php
$count = 5;          // int
$price = 9.99;       // float
$name = "Asha";      // string
$active = true;      // bool
$count = "now text"; // legal: rebinds to a string

Q4. What is the difference between single and double quoted strings?

Double-quoted strings parse the contents: they interpolate variables and expand escape sequences, so "Hi $name\n" inserts the value of $name followed by a newline. Single-quoted strings are almost fully literal, so '$name' prints the raw text dollar-sign-n-a-m-e rather than the variable's value.

Single quotes only interpret \' and \\. They're slightly cheaper because there's no parsing, but the real reason to pick one is intent: use double quotes when you want interpolation, single when you want the literal text.

php
$name = "Asha";
echo "Hi $name";   // Hi Asha
echo 'Hi $name';   // Hi $name
echo "line\n";     // line + newline
echo 'line\n';     // line\n literally

Key point: The follow-up is usually 'which is faster?'. The honest answer: the difference is negligible; pick by whether you need interpolation.

Q5. What is a PHP array and what kinds are there?

A PHP array is an ordered map: it stores key-value pairs and remembers insertion order. The same structure works as an indexed list (integer keys) and an associative array (string keys), so PHP doesn't have separate list and dictionary types.

Indexed arrays use auto-incrementing integer keys starting at 0. Associative arrays use string keys you set yourself. Arrays can also nest to build multidimensional structures.

php
$list = ["a", "b", "c"];        // keys 0, 1, 2
$user = ["name" => "Asha", "age" => 31];

echo $list[0];         // a
echo $user["name"];    // Asha
$grid = [[1, 2], [3, 4]];   // nested

Key point: Saying 'a PHP array is really an ordered map' up front signals you understand the language, not just the syntax.

Watch a deeper explanation

Video: PHP For Beginners | 3+ Hour Crash Course (Traversy Media, YouTube)

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

== compares values after type juggling, so "1" == 1 and 0 == "0" are both true. === compares value and type together, so "1" === 1 is false because one is a string and the other an int.

The rule the question needs: default to ===. Loose comparison hides bugs, especially around 0, empty strings, and null. PHP 8 tightened some of the worst cases (0 == "abc" is now false), but strict comparison is still the safe habit.

php
var_dump("1" == 1);    // true  (type juggling)
var_dump("1" === 1);   // false (different types)
var_dump(0 == "0");    // true
var_dump(0 === "0");   // false

Loose (==) vs strict (===) comparison results

How PHP 8 evaluates a few classic pairs. == juggles types; === also checks type.

== (loose)
3 true results out of 4 pairs
=== (strict)
1 true results out of 4 pairs
  • == (loose): 0=="0", 1=="1", ""==null true; "1"===1 style pair false
  • === (strict): only the same-type-and-value pair is true

Key point: Volunteering that PHP 8 changed 0 == "abc" from true to false shows you track the language, not just memorize old gotchas.

Q7. What is the difference between include and require?

Both pull another file's code into the current script. The difference is failure behavior: include emits a warning and keeps running if the file is missing; require throws a fatal error and halts.

Use require for files the script genuinely can't run without (config, class definitions). Use include for optional pieces. The _once variants (include_once, require_once) skip the file if it's already been included, which prevents duplicate-definition errors.

php
require 'config.php';       // fatal error if missing
include 'sidebar.php';      // warning if missing, continues
require_once 'db.php';      // include only once

Q8. What are superglobals in PHP?

Superglobals are built-in arrays available in every scope without a global declaration. The common ones: $_GET and $_POST for request data, $_SESSION for per-user state, $_COOKIE, $_SERVER for request and environment info, $_FILES for uploads, and $_REQUEST which merges GET, POST, and cookie data.

They're the bridge between the HTTP request and your code. Treat everything in them as untrusted user input: validate and, when it touches a database or HTML, use prepared statements and escaping.

php
$name = $_POST['name'] ?? '';       // form field, POST body
$id = $_GET['id'] ?? null;          // query string ?id=...
$path = $_SERVER['REQUEST_URI'];    // requested path

Key point: The interviewer is listening for 'treat superglobals as untrusted'. Mentioning validation in practice is a security signal.

Q9. What is the difference between GET and POST requests?

GET sends data in the URL query string, so it's visible, bookmarkable, and length-limited. It should be used for reads that don't change state. POST sends data in the request body, isn't shown in the URL, and suits form submissions that create or change data.

In PHP you read them through $_GET and $_POST. The practical rule matches HTTP semantics: GET for fetching, POST for actions with side effects, and never put passwords or sensitive data in a GET URL.

Q10. How do you concatenate strings in PHP?

The concatenation operator is the dot (.), not the plus sign. "Hello" . " " . $name joins strings, and .= appends in place. Using + on strings does arithmetic, coercing numeric strings to numbers.

For building output you can also interpolate inside double quotes, which reads more cleanly than a chain of dots for simple cases.

php
$name = "Asha";
$greeting = "Hi, " . $name . "!";   // Hi, Asha!
$greeting .= " Welcome.";           // append
echo "Hi, $name!";                  // interpolation

Key point: Mixing up . and + is a classic slip for developers coming from JavaScript. Getting it right without hesitation indicates real PHP experience.

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

isset() returns true when a variable exists and is not null. empty() returns true when a variable is unset or holds a falsy value (0, "", "0", null, false, empty array). is_null() returns true only when the value is exactly null.

The trap is empty(): it treats 0 and "0" as empty, which bites when 0 is a valid value. For 'does this key exist and have a value', isset() is usually what you want.

Valueisset()empty()is_null()
unset variablefalsetrueN/A (warning)
nullfalsetruetrue
0 or "0"truetruefalse
"text"truefalsefalse

Key point: The 0-is-empty gotcha is the follow-up. Naming it before you're asked shows you've been burned by it.

Q12. How do you define a function in PHP, and how are default and typed parameters written?

Use the function keyword, a name, parentheses for parameters, and a body. Parameters can have default values and type declarations, and you can declare a return type after a colon.

PHP passes arguments by value by default, so modifying a parameter inside the function doesn't change the caller's variable unless you prefix the parameter with & to pass by reference.

php
function greet(string $name, string $greeting = "Hi"): string {
    return "$greeting, $name";
}

echo greet("Asha");            // Hi, Asha
echo greet("Ben", "Hello");    // Hello, Ben

Q13. How do you define constants in PHP?

Two ways: the define() function and the const keyword. const runs at compile time and works inside classes; define() runs at execution time and can build the name dynamically. Constants have no dollar sign and, once set, can't be changed.

For class-level fixed values, class constants (const RATE = 0.2;) are the norm, accessed with the scope resolution operator (ClassName::RATE).

php
const MAX_USERS = 100;
define("API_URL", "https://example.com");

class Tax {
    const RATE = 0.2;
}
echo Tax::RATE;   // 0.2

Q14. What are the ternary and null-coalescing operators?

The ternary operator condition ? a : b is a compact if/else expression. The short ternary $a ?: $b returns $a if it's truthy, else $b. The null-coalescing operator $a ?? $b returns $a if it exists and is not null, otherwise $b.

The key difference: ?? checks for null and won't warn on undefined array keys or variables, while the short ternary triggers a warning on undefined values and treats any falsy value as the fallback trigger. Use ?? for safe defaults from request data.

php
$page = $_GET['page'] ?? 1;           // 1 if 'page' missing or null
$label = $title ?: 'Untitled';        // 'Untitled' if $title is falsy
$msg = $ok ? 'passed' : 'failed';     // full ternary

Q15. What is type juggling in PHP?

Type juggling is PHP automatically converting a value's type based on context. In arithmetic, the numeric string "5" becomes the int 5. In a boolean context, 0, "", "0", null, and an empty array are all falsy.

It's convenient for web work where everything arrives as a string, but it causes surprises. The defenses are strict comparison (===) and explicit casting ((int)$value) when a type matters.

php
echo "5 apples" + 3;   // 8 in PHP 7; TypeError-adjacent warning in PHP 8
echo "5" + 3;          // 8
var_dump((bool) "0");   // false
var_dump((int) "42px"); // 42

Key point: Note that leading-numeric strings like "5 apples" now raise a warning in PHP 8. Knowing the version boundary is the depth signal here.

Q16. Which array functions should every PHP developer know?

array_map (transform every element), array_filter (keep elements passing a test), array_reduce (fold to a single value), in_array and array_search (membership), array_keys and array_values, array_merge, sort and its variants, and count.

Reaching for these instead of hand-writing loops is a fluency signal. array_map and array_filter together cover most transform-and-filter work in a couple of readable lines.

php
$nums = [1, 2, 3, 4];
$doubled = array_map(fn($n) => $n * 2, $nums);   // [2,4,6,8]
$evens = array_filter($nums, fn($n) => $n % 2 === 0); // [2,4]
$total = array_reduce($nums, fn($c, $n) => $c + $n, 0); // 10

Q17. How does the foreach loop work?

foreach iterates over arrays and iterable objects. foreach ($arr as $value) gives you each value; foreach ($arr as $key => $value) gives you both key and value. It's the idiomatic way to walk an array because it handles both indexed and associative arrays cleanly.

One gotcha: if you take the value by reference (as &$value) to modify elements in place, unset the reference after the loop, or a later reuse of that variable will corrupt the last element.

php
$user = ["name" => "Asha", "role" => "engineer"];
foreach ($user as $key => $value) {
    echo "$key: $value\n";
}
// name: Asha
// role: engineer

Q18. What is the difference between sessions and cookies?

A cookie is a small piece of data stored in the browser and sent back with each request. A session stores data on the server, keyed by a session ID that travels in a cookie. So the browser holds cookie values directly but only holds a session pointer.

Because session data lives server-side, it's safer for sensitive state like a logged-in user's ID. Cookies suit small, non-sensitive preferences. Call session_start() before any output to use $_SESSION.

php
session_start();
$_SESSION['user_id'] = 42;     // stored server-side

setcookie('theme', 'dark', time() + 86400);  // stored in browser

Q19. How do you embed PHP inside HTML?

PHP code goes between <?php and ?> tags, and you can open and close those tags anywhere in an HTML file. The server runs the PHP and leaves the surrounding HTML untouched. There's a short echo tag <?= $value ?> for printing a single value inline.

This mixing is what made PHP popular for templates, though modern apps usually separate logic from templates using an engine like Twig or Blade for readability.

php
<ul>
<?php foreach ($items as $item): ?>
    <li><?= htmlspecialchars($item) ?></li>
<?php endforeach; ?>
</ul>

Q20. How do you write comments in PHP?

PHP supports single-line comments with // or #, and multi-line comments between /* and */. Documentation blocks use /** ... */ with @param and @return tags, which tools and editors read for type hints and API docs.

The docblock style is worth mentioning because it feeds IDE autocompletion and static analysis, which matters on real teams.

Q21. What is the difference between an error and an exception in PHP?

Historically PHP reported problems as errors (warnings, notices, fatal errors) handled through error reporting settings, while exceptions are objects you throw and catch with try/catch. Since PHP 7, most fatal errors became Error objects that implement the same Throwable interface as Exception, so you can catch them too.

The practical split: use exceptions for recoverable, expected failure paths in your own code, and let the error system surface programming mistakes. Catch Throwable only at the top level for logging.

php
try {
    $result = 10 / $divisor;
} catch (DivisionByZeroError $e) {
    echo "cannot divide by zero";
}

Q22. What does htmlspecialchars() do and why does it matter?

htmlspecialchars() converts characters with special meaning in HTML (<, >, &, ") into their entity equivalents. Running user input through it before printing to a page stops that input from being interpreted as markup or script.

It's the core defense against cross-site scripting (XSS). The rule: escape on output, at the point where data enters HTML, and pass ENT_QUOTES so single quotes are handled too.

php
$comment = $_POST['comment'] ?? '';
echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
// <script> becomes &lt;script&gt; and can't run

Key point: Saying 'escape on output' rather than 'sanitize on input' is the more correct framing and interviewers notice it.

Back to question list

PHP Intermediate Interview Questions

Intermediate20 questions

For candidates with working experience: OOP, the type system, standard library judgment, and the questions that separate users from understanders.

Q23. How does PHP implement object-oriented programming?

Classes define properties and methods; the class keyword creates them, new instantiates them, and $this refers to the current instance. PHP supports single inheritance (extends), interfaces (implements), abstract classes, traits for shared behavior, and visibility modifiers public, protected, and private.

Constructors are named __construct(). PHP 8 added constructor property promotion, which declares and assigns properties in the signature, cutting boilerplate. Access static members and constants with the scope resolution operator ::.

php
class Invoice {
    public function __construct(
        private float $total,
        private string $currency = "USD"
    ) {}

    public function format(): string {
        return number_format($this->total, 2) . " " . $this->currency;
    }
}

$inv = new Invoice(199.5);
echo $inv->format();   // 199.50 USD

Key point: Using constructor property promotion in your example signals you write modern PHP 8, not PHP 5 habits.

Watch a deeper explanation

Video: Full PHP 8 Tutorial - Learn PHP The Right Way (Program With Gio, YouTube)

Q24. What do public, protected, and private mean?

These three keywords control where a property or method can be reached. public members are accessible from anywhere, inside or outside the class. protected members are accessible within the declaring class and any subclass that extends it. private members are accessible only inside the declaring class itself, not even in its subclasses.

The convention is to keep properties private or protected and expose behavior through methods, so internal state can change without breaking callers. This is encapsulation, and it's what interviewers are checking when they ask.

ModifierSame classSubclassOutside
publicYesYesYes
protectedYesYesNo
privateYesNoNo

Q25. What is the difference between an abstract class and an interface?

An abstract class can't be instantiated and can mix implemented methods with abstract ones that subclasses must define; a class can extend only one. An interface declares method signatures (and since PHP 8 constants) with no implementation, and a class can implement many.

Use an abstract class to share partial implementation up a single hierarchy. Use an interface to declare a capability that unrelated classes can promise. Modern PHP often reaches for interfaces plus traits over deep abstract hierarchies.

php
interface Exportable {
    public function toArray(): array;
}

abstract class Report implements Exportable {
    abstract public function rows(): array;
    public function count(): int { return count($this->rows()); }
}

Q26. What are traits and when would you use them?

A trait is a bundle of methods (and properties) you can mix into multiple classes with use, giving horizontal code reuse without inheritance. It solves the problem that PHP has single inheritance but you sometimes need to share behavior across unrelated classes.

The caution: traits can hide where behavior comes from and cause method-name collisions, which PHP resolves with insteadof and as. Reach for a trait when the shared code doesn't fit a clean 'is-a' relationship.

php
trait Timestampable {
    public ?string $createdAt = null;
    public function touch(): void {
        $this->createdAt = date('c');
    }
}

class Post {
    use Timestampable;
}

Q27. What are static properties and methods?

static members belong to the class itself, not any instance. A static property is shared across all instances; a static method runs without an object and can't use $this. Access them with the scope resolution operator: ClassName::method() or self:: inside the class.

They suit counters, factory methods, and utility functions. Overuse turns into global state that's hard to test, so the intermediate-level coverage names that trade-off.

php
class Counter {
    private static int $count = 0;
    public static function bump(): int {
        return ++self::$count;
    }
}

Counter::bump();   // 1
Counter::bump();   // 2

Q28. What are magic methods in PHP?

Magic methods are hooks PHP calls automatically at certain moments; their names double underscores comes first. __construct and __destruct handle setup and teardown. __get and __set intercept access to inaccessible properties. __call and __callStatic intercept undefined method calls. __toString controls how an object prints. __invoke lets an object be called like a function.

They power dynamic behavior in ORMs and frameworks. The caution: they make code less explicit and slower, so use them deliberately, not as a default.

php
class Config {
    private array $data = [];
    public function __get($key) { return $this->data[$key] ?? null; }
    public function __set($key, $value) { $this->data[$key] = $value; }
}

$c = new Config();
$c->timeout = 30;      // routes through __set
echo $c->timeout;      // routes through __get

Q29. What is PDO and how does it compare to mysqli?

PDO (PHP Data Objects) is a database access layer that works across many database engines with one API, so switching from MySQL to PostgreSQL means changing the connection string, not the query code. mysqli is MySQL-only.

Both support prepared statements, which is the security-relevant part. PDO's consistent interface and named parameters make it the common default for new code. mysqli still appears in MySQL-specific or legacy projects.

php
$pdo = new PDO('mysql:host=localhost;dbname=app', $user, $pass);
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Key point: 'Why PDO over mysqli?' almost always follows. Lead with database portability and named parameters.

Watch a deeper explanation

Video: PHP For Absolute Beginners | 6.5 Hour Course (Traversy Media, YouTube)

Q30. What are prepared statements and why do they prevent SQL injection?

A prepared statement sends the SQL structure to the database first, with placeholders where data goes, then sends the values separately. Because the query is parsed before the data arrives, user input can't change the query's structure. It's treated purely as data, never as SQL.

That separation is exactly what defeats SQL injection. String-concatenating user input into a query is the vulnerability; binding parameters removes it. This is the single most repeated PHP security question, so The technical detail be automatic.

php
// vulnerable: never do this
$sql = "SELECT * FROM users WHERE name = '$name'";

// safe: value can't alter the query
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = ?');
$stmt->execute([$name]);

Key point: the question needs the mechanism (SQL and data sent separately), not just 'it's safer'. Explain why and you've answered the follow-up.

Q31. Beyond SQL injection, what web security issues should a PHP developer guard against?

The core set: cross-site scripting (XSS), fixed by escaping output with htmlspecialchars; cross-site request forgery (CSRF), fixed with per-form tokens checked on submit; and session hijacking, reduced by regenerating the session ID on login and using secure, HttpOnly cookies.

Also password storage with password_hash() (never plain text or raw md5), input validation, and keeping error display off in production so stack traces don't leak. these is useful because marks a candidate who's shipped real software.

  • XSS: escape on output with htmlspecialchars(..., ENT_QUOTES).
  • CSRF: generate a token per session, embed it in forms, verify it on submit.
  • Passwords: password_hash() to store, password_verify() to check.
  • Sessions: session_regenerate_id(true) on privilege change; HttpOnly and Secure cookie flags.

Q32. How should you store passwords in PHP?

Use password_hash(), which applies a strong, salted, adaptive algorithm (bcrypt by default, Argon2 available) and encodes the salt and cost into the result. Verify with password_verify(), which extracts the parameters and compares safely. Never store plain text, and never use plain md5 or sha1 for passwords.

The adaptive cost matters: it lets you increase work as hardware gets faster, and password_needs_rehash() tells you when to upgrade an existing hash on the user's next login.

php
$hash = password_hash($password, PASSWORD_DEFAULT);
// store $hash

if (password_verify($input, $hash)) {
    // login succeeds
}

Q33. What are namespaces and how does autoloading work?

A namespace groups classes, functions, and constants under a name to avoid collisions between libraries, declared with namespace App\Models; at the top of a file. You reference names with a backslash path or import them with use.

Autoloading loads class files on demand instead of requiring each one. Composer's PSR-4 autoloader maps namespaces to directories, so referencing App\Models\User loads src/Models/User.php automatically. That's why modern PHP projects rarely write manual require lines.

php
namespace App\Models;

class User {
    public function __construct(public string $name) {}
}

// elsewhere
use App\Models\User;
$u = new User('Asha');

Q34. What is Composer and what problem does it solve?

Composer is PHP's dependency manager. composer.json declares your project's packages; composer install reads it, resolves versions, downloads them into vendor/, and generates an autoloader. composer.lock pins exact versions so every machine and CI build gets the same dependency tree.

It also standardized PSR-4 autoloading across the ecosystem, which is why require statements largely disappeared from application code. Knowing the lock-file discipline (commit it for applications) is the mark of production experience.

bash
composer require monolog/monolog   # add a package
composer install                   # install from lock file

# then in code:
# require 'vendor/autoload.php';

Q35. What type declarations does modern PHP support?

PHP supports scalar type hints (int, float, string, bool), array, object, class and interface names, nullable types (?int), union types (int|string, since 8.0), and return types after a colon. Typed properties (public int $count) arrived in 7.4.

declare(strict_types=1) at the top of a file turns off type coercion for that file's function calls, so passing a string where an int is declared throws a TypeError instead of silently converting. Strict types is the recommended default for new code.

php
declare(strict_types=1);

function total(int|float $a, int|float $b): float {
    return (float) ($a + $b);
}

total(2, 3);      // 5.0
total("2", 3);    // TypeError under strict_types

Q36. What is the match expression and how does it differ from switch?

match (PHP 8.0) is an expression that returns a value, compares with strict equality (===), needs no break, and throws if no arm matches (with no default). switch is a statement, uses loose comparison, falls through without break, and doesn't return a value.

match is safer and terser for mapping an input to a result. Reach for switch only when you genuinely want fall-through or need to run several statements per case.

php
$label = match ($status) {
    200, 201 => 'Success',
    404 => 'Not Found',
    500 => 'Server Error',
    default => 'Unknown',
};

Key point: Naming the three real differences (returns a value, strict comparison, no fall-through) is what separates a memorized answer from understanding.

Q37. What are arrow functions and how do they differ from closures?

Arrow functions (fn($x) => $x * 2, since PHP 7.4) are a short single-expression syntax that automatically captures variables from the enclosing scope by value, so you don't write a use clause. A regular closure (anonymous function) can hold multiple statements but must list captured variables explicitly with use.

Use arrow functions for the small callbacks passed to array_map and array_filter. Reach for a full closure when the body needs more than one expression or you must capture by reference.

php
$factor = 3;
$scale = fn($n) => $n * $factor;      // captures $factor automatically
$scale(5);   // 15

$scale2 = function ($n) use ($factor) { return $n * $factor; };

Q38. What are generators in PHP?

A generator is a function that uses yield to produce values one at a time instead of building and returning a whole array. Each iteration resumes right after the last yield, so memory stays flat no matter how many values you produce. It's the tool for streaming large files or infinite sequences.

You iterate a generator with foreach just like an array, but it holds only one value in memory at a time. yield from delegates to another iterable inside a generator.

php
function readLines(string $path): Generator {
    $handle = fopen($path, 'r');
    while (($line = fgets($handle)) !== false) {
        yield rtrim($line);
    }
    fclose($handle);
}

foreach (readLines('huge.log') as $line) {
    // one line in memory at a time
}

Q39. How does passing by value versus by reference work in PHP?

By default PHP passes arguments by value, so a function works on a copy and can't change the caller's variable. Objects are a common point of confusion: the object handle is passed by value, but that handle points to the same object, so property changes are visible outside. It's not the same as passing the variable by reference.

Prefix a parameter with & to pass a real reference, which lets the function reassign the caller's variable. Use it sparingly; functions that mutate their inputs are harder to reason about than functions that return new values.

php
function addTax(float &$price): void {
    $price *= 1.2;      // changes caller's variable
}

$amount = 100.0;
addTax($amount);
echo $amount;   // 120

Key point: The object-handle nuance is the trap. Being able to say 'objects are passed by handle, not by reference' shows real understanding.

Q40. What are variadic functions and the spread operator?

A variadic function collects any number of trailing arguments into an array using ...$args in the signature. The same ... operator spreads an array into individual arguments at a call site, and since PHP 8.1 it can spread string-keyed arrays into named arguments.

This replaced the older func_get_args() approach with something typed and explicit. It's handy for wrappers that forward arguments and for functions that take a variable-length list.

php
function sum(int ...$nums): int {
    return array_sum($nums);
}

sum(1, 2, 3);          // 6
$values = [4, 5, 6];
sum(...$values);       // 15 (spread)

Q41. How do you encode and decode JSON in PHP?

json_encode() turns PHP values into a JSON string; json_decode() parses JSON back. Pass true as the second argument to json_decode to get associative arrays instead of stdClass objects. Since PHP 7.3 you can pass JSON_THROW_ON_ERROR so bad input throws instead of returning null silently.

The common bug is not checking for failure: without the throw flag, a decode error returns null and you carry a null downstream. Objects need __serialize or JsonSerializable to control their JSON shape.

php
$data = ['name' => 'Asha', 'roles' => ['admin', 'user']];
$json = json_encode($data);

$back = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
echo $back['name'];   // Asha

Q42. How do you work with dates and times in PHP?

The object-oriented DateTime and immutable DateTimeImmutable classes are the modern approach: they parse, format, and do arithmetic with clear methods, and DateTimeImmutable avoids the bug where modifying a date accidentally changes another reference to it. DateTimeZone handles time zones explicitly.

The older procedural date() and strtotime() still appear everywhere and are fine for simple formatting. For anything involving arithmetic or time zones, prefer DateTimeImmutable.

php
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
$later = $now->modify('+2 days');
echo $later->format('Y-m-d H:i');
// $now is unchanged: immutability prevents aliasing bugs
Back to question list

PHP Interview Questions for Experienced Developers

Experienced18 questions

advanced rounds probe internals, design judgment, and production scars. Expect every answer here to draw a follow-up.

Q43. Walk through what happens when a PHP request is served.

The web server (Nginx or Apache) receives the HTTP request and hands PHP work to a process manager, usually PHP-FPM. FPM assigns a worker, which bootstraps the script: it parses and compiles the PHP to opcodes (cached by OPcache after the first run), populates the superglobals, runs your code, and returns the output as the response body. Then the worker resets and waits for the next request.

The point interviewers probe is shared-nothing: each request starts with fresh memory and no leftover state from prior requests, which is why long-lived state must live in a database, cache, or session store. That model shapes how you architect a PHP app.

A PHP request, end to end

1Web server receives request
Nginx or Apache passes PHP work to PHP-FPM
2FPM worker bootstraps
compile to opcodes, OPcache serves cached opcodes after first run
3Script runs
superglobals populated, your code executes, output buffered
4Response returned, worker resets
memory cleared: nothing carries to the next request

The shared-nothing reset is the whole point. External stores hold anything that must persist between requests.

Key point: This is really an architecture question. Landing 'shared-nothing, so state lives externally' is what The production-ready answer sounds like.

Q44. What is OPcache and why does it matter for performance?

PHP compiles source to opcodes on every request by default, which is wasted work when the code hasn't changed. OPcache stores the compiled opcodes in shared memory so subsequent requests skip parsing and compilation. On a busy app this is a large, cheap win, and it ships enabled in modern PHP.

The senior-level extras: opcache.validate_timestamps controls whether it re-checks files for changes (turn it off in production and clear the cache on deploy), and preloading (PHP 7.4+) can load framework classes into memory once at startup for a further gain.

Q45. How does PHP manage memory and garbage collection?

PHP uses reference counting: every value tracks how many references point to it, and when the count reaches zero the memory is freed immediately. A cycle collector supplements this to reclaim reference cycles that counting alone can't free, since two objects pointing at each other never reach a zero count.

Because each request is short-lived and its memory is wiped at the end, leaks matter far less than in a long-running process. They still bite in CLI workers and long-running scripts, where you watch for unbounded arrays and circular references and can call gc_collect_cycles() explicitly.

Q46. What are PSR standards and which ones matter?

PSRs are recommendations from the PHP-FIG group that let independent libraries work together. PSR-4 defines autoloading (namespace-to-path mapping), PSR-12 defines coding style, PSR-7 defines HTTP message interfaces, PSR-11 defines a container interface, and PSR-15 defines HTTP middleware.

They're the reason a Symfony component drops into a Laravel app and a PSR-7 request object works across frameworks. Citing the specific ones you use signals you work in the modern ecosystem rather than isolated legacy code.

Q47. What is dependency injection and how is it used in PHP frameworks?

Dependency injection means a class receives its collaborators from outside (usually through the constructor) instead of creating them itself. That inverts control: the class declares what it needs, and a container wires it up. The payoff is testability, since you can pass in a fake database or mailer in tests.

Frameworks like Symfony and Laravel ship a DI container that reads type hints and autowires dependencies. The senior framing is coupling: DI decouples a class from concrete implementations so you can swap them, which is what makes large codebases maintainable.

php
class OrderService {
    public function __construct(
        private PaymentGateway $gateway,
        private Mailer $mailer
    ) {}
    // dependencies passed in, not newed up: easy to test
}

Q48. What did PHP 8.1 and 8.2 add that changed how you model data?

PHP 8.1 introduced enums (real enumerated types, backed or pure, with methods), readonly properties (assignable once then immutable), fibers (a low-level concurrency primitive), and first-class callable syntax. PHP 8.2 added readonly classes and disallowed dynamic properties by default, which catches typo bugs.

The practical shift: enums replace class constants for fixed sets of values, and readonly properties model value objects that can't be mutated after construction. Both make invalid states unrepresentable, which is a real design improvement.

php
enum Status: string {
    case Draft = 'draft';
    case Published = 'published';

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

Status::Published->label();   // Published

Q49. What is late static binding?

Late static binding lets a static reference resolve to the class that was actually called at runtime, not the class where the method is written. self:: is fixed to the defining class, while static:: follows the calling class. It fixes the case where a parent method needs to instantiate or reference the child that invoked it.

The classic use is a static factory in a base class that should return an instance of whichever subclass called it. Without static::, self::new() would always build the base type.

php
class Model {
    public static function create(): static {
        return new static();   // resolves to the calling class
    }
}
class User extends Model {}

$u = User::create();   // instance of User, not Model

Key point: Contrasting self:: (defining class) with static:: (calling class) in one sentence is the crisp answer here.

Q50. How do you resolve method conflicts when combining traits?

When two traits used in the same class define a method with the same name, PHP raises a fatal error unless you resolve it. The insteadof operator picks which trait's version wins, and the as operator aliases the other under a new name so both stay reachable. as can also change a method's visibility.

This is the escape hatch that keeps traits usable when they overlap. Needing it often, though, is a sign the traits are doing too much and a redesign toward composition would read better.

php
trait A { public function hello() { return 'A'; } }
trait B { public function hello() { return 'B'; } }

class C {
    use A, B {
        A::hello insteadof B;
        B::hello as helloB;
    }
}

Q51. How do you build immutable value objects in PHP?

Declare properties readonly (PHP 8.1) or make the whole class readonly (8.2), assign them once in the constructor, and add no setters. Any 'change' returns a new instance with the updated field rather than mutating the current one, the wither pattern. Combine with strict types so the fields can't drift.

Value objects model concepts like Money or an EmailAddress where equality is by value and the object should never change after creation. They remove a class of aliasing bugs and make code easier to reason about.

php
final class Money {
    public function __construct(
        public readonly int $cents,
        public readonly string $currency
    ) {}

    public function add(Money $other): self {
        return new self($this->cents + $other->cents, $this->currency);
    }
}

Q52. What is the N+1 query problem and how do you fix it in PHP?

N+1 happens when you fetch a list of records with one query, then run one more query per record to load a relation, so displaying 100 posts with their authors fires 101 queries. It's the most common performance bug in ORM-backed PHP apps because the extra queries are hidden behind lazy-loaded relations.

The fix is eager loading: fetch the related data up front in one or two queries, typically with a join or an IN clause (Eloquent's with(), Doctrine's fetch join). Spotting it requires looking at the actual query log, which is why query counting in tests is worth adding.

php
// N+1: one query for posts, then one per post for its author
$posts = Post::all();
foreach ($posts as $post) { echo $post->author->name; }

// fixed: eager load authors in a second query
$posts = Post::with('author')->get();

Q53. How do you add caching to a PHP application?

Layer it. OPcache caches compiled opcodes at the runtime level for free. An in-memory store like Redis or Memcached caches expensive query results and computed data across requests, since PHP's shared-nothing model wipes per-request memory. HTTP caching (ETag, Cache-Control) pushes responses to the browser and CDN.

The hard part isn't setting a value, it's invalidation: deciding when cached data is stale. A common pattern is cache-aside with a TTL plus explicit invalidation on writes. Naming the invalidation problem is what marks The production-ready answer.

Q54. Can PHP do asynchronous or concurrent work?

The default model is synchronous and shared-nothing, one request per worker, and that's fine for most web apps because the web server runs many workers in parallel. For concurrency inside a script, PHP 8.1 added fibers (a low-level primitive), and event-loop runtimes like ReactPHP, Amp, and Swoole enable async I/O and long-running processes.

The pragmatic answer: most PHP concurrency is horizontal (more FPM workers) plus a queue system (like a message broker with worker processes) for background jobs. Reach for the async runtimes when you specifically need many concurrent connections or persistent processes, such as WebSockets.

Q55. How do you test a PHP application?

PHPUnit is the standard: test classes with test methods, assertions, data providers for input matrices, and mocks or test doubles for external boundaries like the database and network. Pest is a popular newer layer with a lighter syntax on top of PHPUnit. Structure tests as a pyramid: many fast unit tests, fewer integration tests, a handful of end-to-end.

The judgment interviewers probe: test behavior through public interfaces rather than private internals, and inject dependencies so you can substitute fakes. Add query-count assertions to catch N+1 regressions and use a transaction rollback per test to keep the database clean.

php
use PHPUnit\Framework\TestCase;

class DiscountTest extends TestCase {
    public function test_applies_percentage(): void {
        $this->assertSame(90.0, applyDiscount(100.0, 10));
    }
}

Q56. How do you handle errors and logging in a production PHP service?

Turn display_errors off so stack traces never reach users, set a strict error_reporting level, and convert errors to exceptions with a global handler so nothing fails silently. Log through a structured logger (Monolog is the standard) to a central destination, with context attached to each entry.

Register set_exception_handler and set_error_handler at bootstrap to catch anything uncaught, return a clean error response, and log the detail. The anti-pattern to name is swallowing exceptions with an empty catch, which turns failures into silent data corruption.

php
set_exception_handler(function (Throwable $e) use ($logger) {
    $logger->error($e->getMessage(), ['exception' => $e]);
    http_response_code(500);
    echo 'Something went wrong.';
});

Q57. How does object copying work, and what does __clone do?

Assigning an object ($b = $a) copies the handle, so both variables point to the same object. The clone keyword makes a copy of the object itself, but that copy is shallow: nested objects are still shared between original and clone.

To make nested objects independent, implement __clone(), which PHP calls on the new copy right after cloning, and clone the inner objects there. This is the object-graph version of the shallow-versus-deep copy distinction.

php
class Order {
    public function __construct(public Address $shipTo) {}
    public function __clone() {
        $this->shipTo = clone $this->shipTo;   // deep-copy the inner object
    }
}

Q58. What exactly does declare(strict_types=1) change, and where does it apply?

Without it, PHP coerces scalar arguments to match declared types (passing "5" to an int parameter becomes 5). With strict_types=1, a mismatch throws a TypeError instead; you must pass the exact declared scalar type, with int-to-float widening the one allowed exception.

The subtlety: strict_types applies per file, and specifically to the file where the call is made, not where the function is defined. So enabling it in your file governs how your calls behave, which is why it belongs at the top of every source file in a strict codebase.

Key point: The per-file, call-site scope is the trap. Saying 'it applies to the file making the call, not the definition' is the senior-level detail.

Q59. Design question: how would you structure a REST API in PHP?

Clarify scope first (auth model, versioning, expected load), then layer it: a thin routing and controller layer that only handles HTTP, a service layer with the business logic, and a repository layer for data access. Validate and deserialize input at the edge, return JSON with correct status codes, and keep controllers free of database calls so the logic is testable.

Cross-cutting concerns go in middleware: authentication (token or session), rate limiting, CORS, and logging. Version the API in the URL or a header, use prepared statements throughout, paginate list endpoints, and return consistent error shapes. Structuring the answer clarify, layers, cross-cutting, edges is what the question scores.

php
// controller stays thin: HTTP in, HTTP out
public function show(int $id): JsonResponse {
    $user = $this->users->find($id);   // repository
    if (!$user) {
        return new JsonResponse(['error' => 'Not found'], 404);
    }
    return new JsonResponse($user->toArray());
}

Q60. How do you scale a PHP application under growing traffic?

Scale horizontally first, since the shared-nothing model makes it natural: run more PHP-FPM workers and more servers behind a load balancer, because nothing is held in local memory between requests. Move sessions to a shared store like Redis so any server can serve any user, and put static assets on a CDN.

Then attack the real bottlenecks in order: the database (indexes, read replicas, query fixes for N+1), then caching layers (OPcache, an object cache, HTTP caching), then offloading slow work to a queue with background workers. The senior point is that PHP itself rarely limits you first; the database and I/O do, so measure before you scale anything.

  • Stateless workers: move sessions to Redis so any server handles any request.
  • Database first: it's the usual ceiling. Add indexes, read replicas, fix slow queries.
  • Cache in layers: OPcache, object cache (Redis or Memcached), HTTP and CDN caching.
  • Offload slow work: push email, image processing, and reports to a queue and workers.

Key point: Leading with 'shared-nothing makes horizontal scaling easy, and the database is usually the real limit' is the answer that indicates production experience.

Back to question list

PHP vs Node.js, Python, and Ruby for the web

PHP wins when you want a language purpose-built for the request-response web, cheap hosting everywhere, and a deep ecosystem of mature frameworks and content platforms. Each request starts with a clean slate (the shared-nothing model), which sidesteps a whole class of shared-state bugs but also means PHP leans on external stores for long-lived state. Where it competes closely with Node.js is real-time and streaming work, where a persistent event loop fits better. Knowing these trade-offs out loud is itself an interview signal: it shows you pick tools on merits, not habit.

LanguageConcurrency modelBest atWatch out for
PHPShared-nothing per requestCMS, server-rendered web apps, quick hostingLong-lived state, real-time streams
Node.jsSingle-thread event loopReal-time apps, JSON APIs, one language front to backCPU-bound work blocking the loop
PythonThreads plus the GILData, ML, scripting alongside webRaw web throughput, GIL for CPU parallelism
RubyThreads plus a GIL (MRI)Convention-driven web apps (Rails)Smaller talent pool, runtime speed

How to Prepare for a PHP Interview

Prepare in layers, and practice out loud. Most PHP rounds move from concept questions to live coding to a design or debugging discussion, so rehearse each stage rather than only reading answers.

  • Master your tier's concepts until you can explain them without notes, then read one tier up for the stretch questions.
  • Type and run every snippet in a local PHP install or an online sandbox; modifying working code cements it faster than reading.
  • Practice thinking aloud on small problems with a timer, because your process, not just the final answer is the technical point.
  • Take the quiz on this page to find weak spots, then revisit those questions before the real round.

The typical PHP interview flow

1Recruiter or phone screen
background, motivation, a few concept checks
2Technical concepts
loose comparison, arrays, OOP, sessions, the request lifecycle
3Live coding
write and explain a function under observation
4Design or debugging
trade-offs, reading unfamiliar code, security follow-ups

Earlier rounds increasingly run as AI coding interviews. The concepts on this page are what gets probed at every stage.

Test Yourself: PHP Quiz

Ready to test your PHP knowledge?

10 questions, about 6 minutes. Score 70% or higher to earn a shareable certificate.

10 questions Instant feedback Free certificate on 70%+

Frequently  Asked  Questions

Which PHP topics should I prioritize before a technical round?

Prioritize the areas that change real decisions: fundamentals, practical tasks, debugging, trade-offs, and evidence. The highest-value questions are tied to a project example, a validation check, or a failure mode.

Are these questions enough to pass a PHP interview?

They cover the question-answer portion well, but most PHP rounds also include live coding: writing a function under observation while explaining your thinking. solving small problems out loud with a timer is the practice path. Our AI coding interview prep guide covers that format, including how automated evaluation reads your process.

Which PHP version do these answers assume?

Modern PHP, meaning PHP 8. Features like typed properties, the null-safe operator, match expressions, enums, and readonly properties all come from the 8.x line and show up in current interviews. Where a feature arrived in a specific version, the answer says so. If you're on an older codebase, mention that in the room.

How long does it take to prepare for a PHP interview?

If you use PHP at work or in study, one to two weeks of an hour a day covers this bank with practice runs. Starting colder, plan three to four weeks and write code daily; reading answers without typing them is how preparation quietly fails.

Do interviewers ask exactly these questions?

The concepts repeat far more reliably than the exact wording. Interviewers rephrase, chain follow-ups, and push toward whatever you claim confidence in. Prepare the underlying ideas, loose comparison, arrays, OOP, sessions, and prepared statements, and the phrasing takes care of itself.

Is there a way to test my PHP knowledge?

Yes. The quiz on this page scores you as you go and explains every answer, so you find your weak spots fast. Pass the threshold and you can download a shareable certificate with your name and score, free and with no sign-up. It's the quickest way to check yourself before the real round.

From the team that builds coding interviews

Hyring builds the AI Coding Interviewer that runs live technical rounds in 20+ languages for 5,000+ hiring teams. These PHP questions and scoring notes reflect what actually gets asked and evaluated inside the interviews we host.

See how the AI Coding Interviewer works

Sources

Adithyan RKWritten by Adithyan RK
Surya N
Fact-checked by Surya N
Published on: 3 Jun 2026Last updated: 19 Jun 2026
Share: