PHP Developer interview questions
100 real questions with model answers and explanations for PHP Developer candidates.
See a PHP Developer resume example →Practice with flashcards
Spaced repetition · Hunter Pass
Questions
For user-defined function calls, scalar argument coercion is controlled by the file containing the call, not the file declaring the function.
- A call made from a file with declare(strict_types=1) normally raises TypeError when a scalar argument has the wrong type.
- The declaration applies per file and does not make included files or callers strict automatically.
- An int is still accepted for a float parameter in strict mode and is converted to float.
Why interviewers ask this: The interviewer checks whether you know the caller-side boundary and the deliberate int-to-float exception beyond the basic strict mode definition.
These compound types express alternatives, simultaneous contracts, and combinations of both.
- A union such as A|B accepts a value matching at least one listed type.
- An intersection such as A&B requires an object that is an instance of every listed class or interface type.
- A DNF type such as (A&B)|C is a union whose intersection members are parenthesized.
- PHP rejects redundant or impossible combinations at compile time when it can determine them without autoloading.
Why interviewers ask this: A strong answer distinguishes the three forms and understands why DNF syntax needs explicit grouping.
Nullability controls accepted values, while a default controls whether the caller may omit an argument.
- ?User and User|null both explicitly allow a User instance or null.
- A nullable parameter without a default is still required, while a non-null default does not make its type nullable.
- Declaring User $user = null relies on implicit nullability and is deprecated as of PHP 8.4, so the type should state null explicitly.
Why interviewers ask this: The interviewer evaluates whether you separate nullability from optionality and recognize the modern deprecation.
mixed accepts any value, void promises no meaningful return value, and never promises that execution cannot return normally.
- mixed includes null and therefore cannot be combined redundantly with another union member.
- A void function may use a bare return but cannot return an expression.
- A never function must always throw, terminate execution, or continue indefinitely.
Why interviewers ask this: A strong answer treats these declarations as distinct API contracts rather than interchangeable ways to omit a type.
An overriding method may narrow its return type covariantly and widen its parameter types contravariantly.
- A narrower return still satisfies callers that expect the parent's broader result contract.
- A wider parameter accepts every input valid for the parent and possibly more.
- Reversing either direction would break substitutability and is rejected as an incompatible signature.
Why interviewers ask this: The interviewer checks whether you can connect PHP's variance rules to safe substitution.
A typed property without a default starts uninitialized, which is a separate state from holding null.
- Reading it before assignment raises an Error even when its declared type is nullable.
- A constructor or another valid write must initialize it before normal reads.
- unset() returns a typed property to the uninitialized state, and isset() then reports false.
Why interviewers ask this: The interviewer evaluates whether you understand the runtime state introduced by typed properties rather than treating every missing value as null.
Readonly prevents reassignment of initialized property slots, but it does not make an entire object graph deeply immutable.
- A readonly property must have a declared type and can be initialized only according to PHP's readonly visibility rules.
- A readonly class makes all instance properties readonly and disallows dynamic properties.
- An object stored in a readonly property can still mutate its own internal state.
- Array elements in a readonly property cannot be changed because that operation modifies the property value itself.
Why interviewers ask this: A strong answer distinguishes slot immutability from deep immutability and knows what readonly classes imply.
A unit enum represents named cases only, while a backed enum gives every case a unique int or string value.
- All enums implement UnitEnum and expose cases(), while backed enums also implement BackedEnum.
- A backed case exposes value, and from() or tryFrom() converts a scalar to a case with throwing or nullable failure behavior.
- Enums can define methods and implement interfaces, but they cannot declare properties.
Why interviewers ask this: The interviewer checks whether you understand enum identity, scalar persistence, and the behavioral capabilities of enum types.
Attributes attach structured metadata to declarations, while reflection lets application code discover and interpret that metadata.
- An attribute is a class marked with #[Attribute] and can restrict its allowed targets and repeatability.
- ReflectionAttribute exposes the name and raw arguments without constructing the attribute object.
- Calling newInstance() validates and invokes the attribute constructor, so metadata has no effect unless some consumer reads it.
Why interviewers ask this: A strong answer separates declarative metadata from the reflection-driven code that gives it behavior.
Use an interface for a capability contract across unrelated types and an abstract class when related subclasses also need shared implementation or state.
- A class can implement several interfaces but can extend only one class.
- An abstract class may provide constructors, properties, concrete methods, and abstract method requirements.
- Depending on interfaces at public boundaries usually preserves more freedom to replace implementations.
Why interviewers ask this: The interviewer evaluates whether you choose inheritance for genuine shared structure rather than using it as the default contract mechanism.
Multiple focused interfaces let a class expose only the capabilities that each client actually needs.
- PHP permits one class to implement any number of compatible interfaces despite single class inheritance.
- Interface segregation avoids forcing implementations to provide irrelevant methods or throw unsupported-operation errors.
- Small contracts produce narrower dependencies and simpler test doubles at call sites.
Why interviewers ask this: A strong answer connects PHP's multiple-interface support to interface segregation and lower coupling.
A trait supplies reusable implementation to a class, whereas an interface defines behavior that consumers may rely on.
- Using a trait copies its methods and properties into the consuming class's composition model.
- A trait does not create a standalone runtime type that a parameter can require.
- A class can implement an interface without sharing code, or use a trait while still declaring the interface explicitly.
Why interviewers ask this: The interviewer checks whether you separate code reuse from polymorphic contracts.
PHP requires explicit adaptation when imported traits provide methods with the same name.
- The insteadof operator selects one trait's implementation over another conflicting implementation.
- The as operator creates an alias or changes the imported method's visibility without renaming the original method.
- Aliasing the losing method preserves access to both implementations when each has a distinct purpose.
Why interviewers ask this: A strong answer knows that insteadof chooses an implementation while as adapts access to one.
Static members belong to class-level state and behavior rather than to one object instance.
- A static method has no $this and should receive any instance-specific collaborators explicitly.
- A mutable static property can be observed across calls and objects, creating hidden coupling and test isolation problems.
- Inheritance, redeclaration, and late static binding affect which class-level member is addressed, so shared state should not be assumed casually.
Why interviewers ask this: The interviewer evaluates whether you understand static members as shared dependencies with inheritance-sensitive behavior.
self:: resolves relative to the class where the method is declared, while static:: uses the class named by the runtime call through late static binding.
- A method inherited by a child still treats self as the declaring class.
- static:: and new static() allow an inherited implementation to honor the called subclass.
- Use self when the implementation must be fixed to its declaring class and static when deliberate subclass customization is part of the contract.
Why interviewers ask this: A strong answer explains late static binding as called-class resolution rather than merely different syntax.
final closes selected extension points when an implementation or invariant must not be changed by subclasses.
- A final class cannot be extended, while a final method cannot be overridden in an otherwise extensible class.
- A final class constant prevents descendants from redefining that constant.
- final does not make object state immutable and should express a design boundary rather than block extension without reason.
Why interviewers ask this: The interviewer checks whether you use final as a precise contract tool instead of confusing it with readonly.
PHP invokes __get and __set when code reads or writes an inaccessible or nonexistent instance property.
- __get receives the property name and returns the exposed value, while __set receives both the name and assigned value.
- Accessing the same unresolved property inside its hook can recurse or produce confusing behavior.
- Magic properties hide the real object shape from type checks, refactoring tools, and readers unless the boundary is kept narrow.
Why interviewers ask this: A strong answer knows both the dispatch condition and the maintainability cost of virtual properties.
They intercept calls to inaccessible or nonexistent methods in instance and static contexts respectively.
- Each hook receives the requested method name and an array of supplied arguments.
- They can implement proxies or constrained dynamic APIs, but they also risk hiding misspellings until runtime.
- Explicit methods or generated adapters are preferable when the supported operation set is stable and should be visible to tools.
Why interviewers ask this: The interviewer evaluates whether you understand dynamic method dispatch without overlooking its weak discoverability and validation.
These hooks define existence checks and removal behavior for inaccessible or nonexistent instance properties.
- isset() and empty() can invoke __isset, whose boolean result should match the object's virtual-property semantics.
- unset() invokes __unset, which can remove or clear the corresponding internal value.
- Their behavior should stay consistent with __get and __set, especially when null has a distinct domain meaning.
Why interviewers ask this: A strong answer treats the four property hooks as one coherent virtual-property contract.
__invoke makes an object callable, while __toString defines its conversion in a string context.
- An invokable object can retain dependencies or configuration while being passed wherever a callable is accepted.
- __toString must return a string and PHP automatically treats a class declaring it as Stringable.
- String conversion should be predictable and side-effect free because logging, interpolation, and concatenation may trigger it implicitly.
Why interviewers ask this: The interviewer checks whether you understand both language hooks and can design their implicit behavior safely.
Locked questions
- 21
What exactly happens when a PHP object is cloned?
php - 22
How do == and === compare objects in PHP?
php - 23
How do dependency inversion and composition over inheritance improve PHP OOP design?
oopphpdesign - 24
How does closure capture by value differ from capture by reference in PHP?
closuresphp - 25
What does closure binding change in PHP?
closuresphp - 26
How do first-class callable expressions differ from traditional callable syntax in PHP?
php - 27
Why can generators use less memory than building an array?
generatorsmemory - 28
How do yield keys and yield from delegation behave?
delegationgenerators - 29
What does one-pass iteration mean for a PHP Generator, and how is its return value read?
generatorsiterationphp - 30
How are Throwable, Error, and Exception related in modern PHP?
error-handlingphp - 31
How should a custom exception hierarchy represent domain failures?
error-handling - 32
How do catch ordering and union catches affect exception handling in PHP?
error-handlingphpunion - 33
What does finally guarantee, and why is return inside finally dangerous?
- 34
How does exception chaining preserve an original failure in PHP?
error-handlingphp - 35
How do native and emulated PDO prepared statements differ?
pdo - 36
What is the difference between PDOStatement::bindValue and bindParam?
- 37
What can PDO placeholders represent, and what must be built dynamically instead?
pdo - 38
How do PDO transactions change autocommit and define an ACID boundary?
transactionsacidpdo - 39
How do transaction isolation levels relate to dirty reads, non-repeatable reads, and phantoms?
transactions - 40
How can nested transaction semantics be modeled when PDO has no portable nested transactions?
transactionspdo - 41
Why can DDL statements make PDO transaction code nonportable?
transactionspdo - 42
What makes a PHP session identifier resistant to fixation and guessing?
sessionsphp - 43
What protection do Secure, HttpOnly, and SameSite add to a PHP session cookie, and what do they not solve?
sessionscookiesphp - 44
Why does session-based authentication need CSRF protection, and what properties should a token have?
authcsrftokens - 45
How do Composer constraints, the lock file, dependency sections, install, and update work together?
dependenciespackagingcomposer - 46
How do PSR-4 autoloading and Composer's optimized or authoritative class maps differ?
psrautoloadingoptimization - 47
What is the purpose and scope of PSR-12?
psr - 48
What is the conceptual HTTP request lifecycle shared by Laravel and Symfony applications?
laravelsymfonyhttp - 49
What dependency injection container and autowiring concepts are shared by Laravel and Symfony?
laravelsymfonydependency-injection - 50
How do OPcache, timestamp revalidation, preloading, and JIT differ?
opcache - 51
How would you create an order atomically and publish an event without a dual-write failure?
concurrency - 52
How would you design a REST create endpoint with DTOs, validation, authorization, and clear statuses?
authvalidationrest - 53
How would you protect a webhook from forgery, replay, and duplicate delivery?
webhooks - 54
How would you implement asynchronous email with retries, idempotency, and terminal failure handling?
idempotencyasync - 55
How would you build a safe filter, sort, and pagination endpoint?
endpointspagination - 56
How would you import a large CSV in batches while reporting row errors and progress?
batch - 57
How would you map exceptions to API errors without leaking internals?
error-handling - 58
How would you build a resilient external payment client with clear failure states?
- 59
How would you debug memory growth in a long-running PHP worker?
memoryphp - 60
How would you stream a very large CSV export without exhausting PHP memory?
memoryphp - 61
How would you profile a slow PHP request and separate database, CPU, and I/O time?
databasephp - 62
How would you diagnose an intermittent 500 that cannot be reproduced immediately?
- 63
A Composer class works locally but fails on Linux; what would you investigate?
composer - 64
How would you reduce memory use caused by PHP arrays and copy-on-write behavior?
memoryphp - 65
How would you protect requests when an external API becomes slow?
api - 66
A TypeError occurs only for some payloads; how would you find and fix it?
- 67
How would you detect and fix Eloquent or Doctrine N+1 queries?
n+1queriesorm - 68
How would you inspect a slow SQL query through PDO using EXPLAIN?
sqlqueriespdo - 69
How would you choose a composite index for WHERE filters plus ORDER BY?
indexes - 70
How would you handle a database deadlock in PHP?
databaselockingphp - 71
How would you perform an efficient and safe bulk insert with PDO?
pdo - 72
How would you replace offset pagination with keyset pagination?
pagination - 73
Would you use PDO persistent connections in PHP-FPM?
pdophp-fpmphp - 74
How would you keep external network calls outside a database transaction while preserving consistency?
databasetransactionsconsistency - 75
How would you implement optimistic locking with a version column?
lockingschema - 76
How would you build optional dynamic filters with PDO safely?
pdo - 77
How would you prevent SQL injection with dynamic sort columns and directions?
sqlschemainjection - 78
How would you prevent reflected and stored XSS in Blade or Twig?
templatingxss - 79
Where should CSRF protection apply, and how does a bearer-token API differ?
csrftokensapi - 80
How do validation, normalization, and escaping belong at different boundaries?
normalizationvalidation - 81
How would you prevent Eloquent mass assignment and overposting?
orm - 82
How would you harden login session creation and logout?
sessions - 83
How would you prevent IDOR on an endpoint accepting a resource ID?
endpoints - 84
How would you secure a PHP file upload?
php - 85
How would you implement a secure password-reset flow?
passwords - 86
How would you keep Laravel or Symfony controllers thin and define transaction boundaries?
laravelsymfonytransactions - 87
How would you bind an interface in Laravel and when use contextual binding?
laraveltypes - 88
How would you configure Symfony autowiring for an interface?
symfonytypesconfig - 89
How would you order proxy trust, authentication, rate limiting, CSRF, and authorization middleware?
authcsrfmiddleware - 90
Where would you place Eloquent scopes and business rules without bloated models or repository ceremony?
orm - 91
How would you process a large Doctrine dataset in batches?
ormbatchconcurrency - 92
How would you dispatch side effects only after a transaction commits?
transactions - 93
How would you unit test an application service with PHPUnit?
unit - 94
How would you write a database integration test with real schema and isolation?
databaseschemaintegration - 95
How would you feature-test validation, authorization, success, and side effects?
authvalidation - 96
How would you use PHPUnit data providers for boundary and malformed inputs?
testing - 97
How would you remove flaky time and randomness from tests?
flaky - 98
How would you implement Redis cache-aside with stampede protection?
rediscaching - 99
How would you keep cache correct after database writes?
databasecaching - 100
How would you deploy PHP safely with OPcache enabled?
opcachedeploymentphp