PHPInterview Questions

PHP Interview Questions

These are the kinds of questions that come up repeatedly in PHP interviews, roughly ordered from fundamentals to more advanced territory. The goal of each answer here isn't to recite a dictionary definition — it's to explain the reasoning well enough that you could adapt it to a follow-up question, which is usually what actually distinguishes a strong answer from a memorized one.

Beginner

What's the difference between == and ===?

== compares two values after converting them to a common type if they differ, which can produce surprising results (like "0" and false being loosely equal). === compares both the value and the type, returning true only when both match exactly with no conversion. In practice, === should be the default choice, with == reserved for the rare case where loose comparison is genuinely what's needed.

What's the difference between an indexed array and an associative array?

PHP has a single array type under the hood, but it's used two ways. An indexed array uses sequential integer keys starting at 0, assigned automatically when you don't specify a key ([10, 20, 30]). An associative array uses explicit keys you choose, typically strings, to describe what each value means (['name' => 'Ada', 'age' => 30]). Both are the same underlying ordered map structure — the difference is purely which keys you assign.

What is the difference between include and require?

Both pull the contents of another PHP file into the current script. The difference is what happens when the file can't be found: include raises a warning and lets the script continue running, while require raises a fatal error and stops execution immediately. require is the safer choice for files the application can't function without, like a configuration file or a class definition; include suits genuinely optional content.

What does isset() check, and how is it different from empty()?

isset() checks whether a variable exists and is not null, returning false for a variable that was never set or was explicitly set to null. empty() checks whether a variable is "falsy" — it returns true for null, false, 0, '0', an empty string, and an empty array, in addition to an unset variable. They answer different questions: isset() asks "does this have a value at all," empty() asks "is this value effectively nothing."

What is a superglobal? Name a few.

A superglobal is a built-in array that's automatically available in every scope in a PHP script, without needing to be declared global. Common ones include $_GET and $_POST (request data), $_SESSION (data persisted across requests for one user), $_COOKIE (data stored in the browser), $_SERVER (request and server environment information), and $_FILES (uploaded file data).

Intermediate

Explain the difference between an abstract class and an interface.

An interface declares a contract — method signatures with no implementation — that any implementing class must fulfill; a class can implement multiple interfaces. An abstract class can mix fully implemented methods with abstract ones that subclasses must fill in, and it can hold shared state through properties, but a class can only extend one abstract class. The practical rule of thumb: use an interface to describe "what a class can do," and an abstract class when you also want to share concrete behavior across related subclasses.

What is the difference between a static method and an instance method?

An instance method belongs to a specific object and can read or modify that object's properties through $this. A static method belongs to the class itself rather than to any particular instance, is called without creating an object (ClassName::method()), and has no access to $this. Static methods are useful for behavior that doesn't depend on any instance's state, like a factory method or a pure utility function.

What does password_hash() do, and why shouldn't you write your own hashing?

password_hash() takes a plaintext password and returns a salted hash generated with a strong algorithm (bcrypt by default, or Argon2id if requested), automatically embedding a random salt and the algorithm's cost parameters in the output string. password_verify() then checks a submitted password against that stored hash without you ever needing to extract the salt yourself. Writing custom hashing risks subtle mistakes — a fast, unsalted hash like plain MD5 or SHA-256 is crackable at massive scale using precomputed tables, whereas password_hash() is deliberately slow and salted per password to resist exactly that.

What is the difference between require_once and require?

require pulls in a file every time that line executes, even if the file was already included earlier — including the same file twice this way causes fatal "cannot redeclare" errors for any classes or functions inside it. require_once tracks which files have already been included and skips re-including a file it has already loaded, which is why it's the standard choice for pulling in class definitions that might otherwise get included from multiple code paths.

What are traits, and what problem do they solve?

A trait is a reusable block of methods that can be mixed into a class with the use keyword, without needing inheritance. PHP only supports single inheritance, so if two unrelated classes need to share the same behavior — logging, timestamps, a common utility method — they can't both extend a shared base class if they already extend something else. A trait sidesteps that by letting the same method implementation be pulled into multiple, otherwise unrelated, classes.

What is namespacing, and why does PHP need it?

A namespace groups related classes, functions, and constants under a common prefix, similar to a folder path (App\Billing\Invoice). It exists to prevent naming collisions — without namespaces, two libraries that both define a class named Logger couldn't be used in the same project. Namespaces let each library define names freely within its own namespace, and code that uses them refers to the fully qualified name or imports it with a use statement.

Advanced

What is late static binding, and what problem does it solve?

In an inherited method, self:: always refers to the class where the method is physically defined, even if it's called on a subclass — which is a problem for patterns like factory methods that should return an instance of whichever subclass was actually called. Late static binding, invoked with static:: instead of self::, resolves to the class that was actually called at runtime, so a method defined once in a parent class can correctly instantiate or reference the calling subclass rather than always the parent.

self:: vs. static:: with late static binding

PHP
<?php
class Model
{
    public static function create(): static
    {
        return new static(); // resolves to the calling subclass
    }
}

class User extends Model
{
}

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

Explain the difference between shallow copy and how PHP objects are actually passed around.

Assigning an array to a new variable in PHP copies it by value — modifying the copy doesn't affect the original. Objects behave differently: a variable holding an object actually holds a handle to it, so assigning that variable to another one gives you a second handle to the same object, and modifying it through either variable affects the same underlying data. Explicitly cloning an object with clone creates a genuinely separate copy, though by default that clone is still shallow — any properties that are themselves objects still point to the same nested objects unless you implement __clone() to deep-copy them.

What are magic methods? Name a few and what they're for.

Magic methods are methods PHP calls automatically in specific situations, always prefixed with two underscores. __construct() and __destruct() run on object creation and destruction. __get() and __set() intercept access to properties that aren't declared or aren't accessible, useful for building dynamic or lazily-computed properties. __call() intercepts calls to methods that don't exist on the object, which is how many libraries implement flexible, dynamic-feeling APIs. __toString() defines what happens when an object is used in a string context, like being echoed directly.

What is dependency injection, and why prefer it over creating dependencies inside a class?

Dependency injection means a class receives the objects it depends on from the outside — typically through its constructor — rather than constructing them itself internally. When a class builds its own dependency, that dependency is invisible from the outside and effectively hardcoded, making it difficult to substitute a test double or swap implementations later. Injecting dependencies makes them explicit in the constructor signature, and lets a test pass in a fake version without needing to modify the class itself.

What's the difference between == , ===, and the spaceship operator <=>?

== and === have already been covered as value and value-plus-type comparisons. The spaceship operator <=> is a three-way comparison: it returns a negative number if the left side is smaller, zero if they're equal, and a positive number if the left side is larger. It's mainly used inside sorting callbacks, where usort() expects a callback returning exactly this kind of negative/zero/positive result, letting you write $a['price'] <=> $b['price'] instead of a longer if/elseif chain.

Tip
For any question like these, a strong answer doesn't stop at the definition — it explains the concrete problem the feature exists to solve. Interviewers are usually listening for whether you understand *why* a piece of language design exists, not just whether you can recite what it does.