PHP Interview Questions Overview
PHP powers 77% of websites with a server-side language (including WordPress, Facebook’s HHVM era, Shopify’s partner ecosystem, and Wikipedia). Modern PHP (8.0+) is significantly different from legacy PHP 5 — senior interviews test modern OOP, type safety, performance patterns, and PHP 8 features. This guide covers what you will actually be asked.
Object-Oriented Programming
What is the difference between abstract classes and interfaces in PHP?
An interface defines a contract (method signatures) with no implementation. A class can implement multiple interfaces. An abstract class can have both abstract methods (no implementation, must be overridden) and concrete methods (with implementation). A class can extend only one abstract class. Use interfaces for capability contracts (Countable, Serializable); use abstract classes when you want to provide shared implementation that subclasses customize.
interface Exportable {
public function toArray(): array;
public function toJson(): string;
}
abstract class BaseReport implements Exportable {
abstract protected function fetchData(): array;
public function toJson(): string {
return json_encode($this->toArray()); // concrete implementation
}
// toArray() still abstract — subclasses implement it
}
What are traits in PHP?
Traits are a mechanism for code reuse in single-inheritance languages. A trait is like a partial class — it defines methods that can be mixed into any class. Unlike interfaces, traits contain implementation. A class can use multiple traits. PHP resolves conflicts with insteadof and as keywords.
trait Timestampable {
private ?DateTime $createdAt = null;
private ?DateTime $updatedAt = null;
public function touch(): void {
$now = new DateTime();
if ($this->createdAt === null) {
$this->createdAt = $now;
}
$this->updatedAt = $now;
}
public function getUpdatedAt(): ?DateTime {
return $this->updatedAt;
}
}
class Order {
use Timestampable;
// now has touch(), getUpdatedAt() etc.
}
PHP 8 Features
Named arguments
// Instead of remembering parameter order:
array_slice(array: $arr, offset: 2, length: 5, preserve_keys: true);
// Call functions with any subset of optional parameters:
htmlspecialchars(string: $str, double_encode: false);
Nullsafe operator
// Before PHP 8:
$city = null;
if ($user !== null && $user->getAddress() !== null) {
$city = $user->getAddress()->getCity();
}
// PHP 8 nullsafe operator:
$city = $user?->getAddress()?->getCity(); // returns null if any link is null
Match expression (PHP 8.0)
$status = match($statusCode) {
200, 201 => "success",
301, 302 => "redirect",
404 => "not_found",
500 => "server_error",
default => "unknown",
};
// Unlike switch: strict comparison (===), no fallthrough, exhaustive
Enums (PHP 8.1)
enum Status: string {
case Draft = "draft";
case Published = "published";
case Archived = "archived";
public function label(): string {
return match($this) {
Status::Draft => "Draft",
Status::Published => "Published",
Status::Archived => "Archived",
};
}
}
$status = Status::Published;
echo $status->value; // "published"
echo $status->label(); // "Published"
Status::from("draft"); // Status::Draft
Fibers (PHP 8.1): Cooperative Multitasking
$fiber = new Fiber(function(): void {
$value = Fiber::suspend("first"); // suspend, return "first" to caller
echo "Got: {$value}n"; // resumed with "hello"
Fiber::suspend("second");
});
$result = $fiber->start(); // "first"
$result = $fiber->resume("hello"); // "second", prints "Got: hello"
Fibers are PHP’s primitive for cooperative multitasking — the foundation for async frameworks like ReactPHP and Amphp. Unlike goroutines, PHP fibers require explicit suspend/resume (no automatic I/O yielding). Libraries built on fibers can implement async/await patterns similar to JavaScript.
Type System
// PHP 8 union types:
function processId(int|string $id): User|null {
return User::find($id);
}
// PHP 8.1 intersection types (must satisfy ALL types):
function process(Iterator&Countable $collection): void { }
// PHP 8 readonly properties (PHP 8.1):
class User {
public function __construct(
public readonly int $id,
public readonly string $email,
) {}
}
// $user->id = 5; // Error: Cannot modify readonly property
// Nullables:
function find(int $id): ?User { ... } // returns User or null
Generators
Generators produce values lazily without storing all values in memory. A function with yield is a generator. Useful for processing large datasets row by row or generating infinite sequences.
function readLargeFile(string $path): Generator {
$handle = fopen($path, "r");
while (($line = fgets($handle)) !== false) {
yield $line; // suspend here, resume on next()
}
fclose($handle);
}
// Process a 10GB file with O(1) memory:
foreach (readLargeFile("/var/log/access.log") as $line) {
processLine($line);
}
// No array_map() on 50M lines — generator pulls one line at a time
Performance Optimization
OpCache
PHP normally parses and compiles source files on every request. OpCache stores compiled bytecode in shared memory — subsequent requests skip parsing and compilation. Enable in php.ini: opcache.enable=1, opcache.memory_consumption=256, opcache.validate_timestamps=0 (production — no file stat checks). 2-5× throughput improvement on typical applications.
Database Query Optimization
// Use PDO prepared statements (cache query plan + prevent SQL injection):
$stmt = $pdo->prepare("SELECT * FROM orders WHERE user_id = ? AND status = ?");
$stmt->execute([$userId, $status]);
// Avoid N+1: fetch related data in one query
$orders = $pdo->query("
SELECT o.*, u.name as user_name
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.created_at > NOW() - INTERVAL 7 DAY
")->fetchAll();
Caching with Redis
function getUser(int $id): array {
$key = "user:{$id}";
$cached = $redis->get($key);
if ($cached !== false) {
return json_decode($cached, true);
}
$user = $db->fetchUser($id); // slow DB query
$redis->setex($key, 3600, json_encode($user)); // cache 1 hour
return $user;
}
Composer and Dependency Management
Composer is PHP’s dependency manager. Key commands: composer require vendor/package installs a package and updates composer.json and composer.lock. composer install (CI/production) installs exact versions from composer.lock. composer update updates to latest allowed versions and regenerates composer.lock. Autoloading: Composer generates a PSR-4 autoloader from the autoload section in composer.json — class names map to file paths based on namespace prefixes.
// composer.json:
{
"autoload": {
"psr-4": {
"App": "src/"
}
}
}
// AppServicesOrderService → src/Services/OrderService.php
Key Interview Takeaways
- Traits provide multiple-inheritance-like reuse; interfaces define pure contracts; abstract classes provide partial implementation
- PHP 8.1 enums are first-class types with methods — replace string constants
- Fibers enable cooperative multitasking; foundation for async frameworks
- Generators process large datasets in O(1) memory via lazy evaluation
- OpCache is essential in production — disable validate_timestamps for performance
- Readonly properties (PHP 8.1) enforce immutability on value objects