PHP Interview Questions
44 questions with detailed answers
Question:
Answer:
The father of PHP is Rasmus Lerdorf.
Background:
- Created PHP in 1994 as "Personal Home Page"
- Originally a set of Common Gateway Interface (CGI) binaries written in C
- Later evolved into "PHP: Hypertext Preprocessor" (recursive acronym)
Evolution Timeline:
1994: PHP/FI (Personal Home Page/Forms Interpreter)
1997: PHP/FI 2.0 - Zeev Suraski and Andi Gutmans joined
1998: PHP 3.0 - Complete rewrite
2000: PHP 4.0 - Zend Engine
2004: PHP 5.0 - Zend Engine II, OOP support
2015: PHP 7.0 - Major performance improvements
2020: PHP 8.0 - JIT compiler, union types
2023: PHP 8.3 - Latest stable version
Current Status: PHP powers over 70% of websites worldwide, including Facebook, Wikipedia, and WordPress.
Question:
Answer:
A session is a server-side storage mechanism that maintains user data across multiple HTTP requests.
How Sessions Work:
// Start a session
session_start();
// Store data in session
$_SESSION["username"] = "john_doe";
$_SESSION["user_id"] = 123;
$_SESSION["role"] = "admin";
// Access session data
echo "Welcome " . $_SESSION["username"];
// Check if session variable exists
if (isset($_SESSION["user_id"])) {
echo "User is logged in";
}
// Destroy session
session_destroy();
Session Configuration:
// Set session parameters
ini_set("session.cookie_lifetime", 3600); // 1 hour
ini_set("session.gc_maxlifetime", 3600);
ini_set("session.cookie_secure", 1); // HTTPS only
ini_set("session.cookie_httponly", 1); // No JavaScript access
// Custom session handler
session_set_save_handler(
"session_open",
"session_close",
"session_read",
"session_write",
"session_destroy",
"session_gc"
);
Benefits: Server-side security, larger storage capacity, automatic cleanup, cross-page data persistence.
Question:
Answer:
PEAR (PHP Extension and Application Repository) is a framework and distribution system for reusable PHP components.
Installation and Usage:
// Install PEAR package
pear install Mail
pear install DB
// Using PEAR Mail package
require_once "Mail.php";
$recipients = "user@example.com";
$headers["From"] = "sender@example.com";
$headers["Subject"] = "Test Email";
$body = "This is a test email";
$mail = Mail::factory("smtp", [
"host" => "smtp.gmail.com",
"port" => 587,
"auth" => true,
"username" => "your_email@gmail.com",
"password" => "your_password"
]);
$result = $mail->send($recipients, $headers, $body);
PEAR Database Example:
require_once "DB.php";
$dsn = "mysql://username:password@localhost/database";
$db = DB::connect($dsn);
if (PEAR::isError($db)) {
die("Connection failed: " . $db->getMessage());
}
// Execute query
$result = $db->query("SELECT * FROM users WHERE active = 1");
while ($row = $result->fetchRow()) {
echo $row[0] . " - " . $row[1] . "\n";
}
Modern Alternative: Composer has largely replaced PEAR for dependency management in modern PHP development.
Question:
Answer:
Fatal errors:
These are critical errors. Example: instantiating an object of a class which does not exist or a non-existent function is called. These errors results in termination of the script immediately and default behavior of PHP is shown to them when they take place. Twelve different error types are used to represent these variations internally.
Warnings:
These are serious errors. Example: attempting to include () file which is not available. These errors are showed to the user by default but they will not result in ending the script.
Notices:
These errors are non-critical and trivial errors that come across while executing the script in PHP. Example: trying to gain access the variable which is not defined. These errors are not showed to the users by default even if the default behavior is changed.
Question:
Answer:
A cookie is destroyed by setting its expiration time to a past date.
Methods to Destroy Cookies:
// Method 1: Set expiration to past time
setcookie("username", "", time() - 3600); // 1 hour ago
setcookie("user_id", "", time() - 1); // 1 second ago
// Method 2: Set expiration to Unix epoch
setcookie("session_token", "", 1);
// Method 3: Using current time minus any value
setcookie("preferences", "", time() - 86400); // 24 hours ago
Complete Cookie Management:
// Create cookie with expiration
setcookie("user_data", "john_doe", [
"expires" => time() + 3600, // 1 hour
"path" => "/",
"domain" => ".example.com",
"secure" => true, // HTTPS only
"httponly" => true, // No JavaScript access
"samesite" => "Strict" // CSRF protection
]);
// Check if cookie exists
if (isset($_COOKIE["user_data"])) {
echo "Cookie value: " . $_COOKIE["user_data"];
}
// Destroy specific cookie
function destroyCookie($name, $path = "/", $domain = "") {
setcookie($name, "", [
"expires" => time() - 3600,
"path" => $path,
"domain" => $domain
]);
unset($_COOKIE[$name]);
}
// Destroy all cookies
foreach($_COOKIE as $name => $value) {
destroyCookie($name);
}
Important: The path and domain must match the original cookie settings for successful deletion.
Question:
Answer:
Both require and include are used for file inclusion, but they handle errors differently.
Key Differences:
| Feature | include | require |
|---|---|---|
| Error Handling | Warning (E_WARNING) | Fatal Error (E_COMPILE_ERROR) |
| Script Execution | Continues after error | Stops after error |
| Use Case | Optional files | Critical files |
Practical Examples:
// include - script continues even if file not found
include "optional_config.php";
echo "This will execute even if file missing";
// require - script stops if file not found
require "database_config.php";
echo "This won't execute if file missing";
// include_once - includes file only once
include_once "functions.php";
include_once "functions.php"; // Won't include again
// require_once - requires file only once
require_once "constants.php";
require_once "constants.php"; // Won't require again
Best Practices:
// Use require for critical files
require_once "config/database.php";
require_once "classes/User.php";
// Use include for optional files
include "templates/header.php";
include "widgets/sidebar.php";
// Error handling with include
if (!include "optional_module.php") {
echo "Module not available, using default";
}
Performance: require_once and include_once are slightly slower due to file tracking overhead.
Question:
Answer:
The header() function sends raw HTTP headers to the client browser.
Common Use Cases:
// 1. Page Redirection
header("Location: https://example.com/dashboard");
exit(); // Always use exit after redirect
// 2. Set Content Type
header("Content-Type: application/json");
echo json_encode(["status" => "success"]);
// 3. Force File Download
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"report.pdf\"");
header("Content-Length: " . filesize("report.pdf"));
readfile("report.pdf");
// 4. Cache Control
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
// 5. HTTP Status Codes
header("HTTP/1.1 404 Not Found");
header("HTTP/1.1 500 Internal Server Error");
Security Headers:
// CORS headers
header("Access-Control-Allow-Origin: https://trusted-site.com");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
// Security headers
header("X-Frame-Options: DENY");
header("X-XSS-Protection: 1; mode=block");
header("X-Content-Type-Options: nosniff");
header("Strict-Transport-Security: max-age=31536000");
// Content Security Policy
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'");
Important Notes:
- Must be called before any output (HTML, echo, print)
- Use exit() after redirect headers
- Headers are case-insensitive
- Can be overwritten by calling header() again
Question:
Answer:
GET and POST are HTTP methods for sending data between client and server.
Detailed Comparison:
| Feature | GET | POST |
|---|---|---|
| Data Location | URL query string | Request body |
| Data Limit | ~2048 characters | No practical limit |
| Security | Less secure (visible) | More secure (hidden) |
| Caching | Can be cached | Not cached |
| Bookmarking | Can be bookmarked | Cannot be bookmarked |
| Idempotent | Yes | No |
GET Method Examples:
// URL: https://example.com/search.php?q=php&category=tutorial
// Accessing GET data
$searchQuery = $_GET["q"] ?? "";
$category = $_GET["category"] ?? "all";
// Validate and sanitize
$searchQuery = filter_var($searchQuery, FILTER_SANITIZE_STRING);
if (strlen($searchQuery) > 100) {
$searchQuery = substr($searchQuery, 0, 100);
}
// Build search results
$results = searchDatabase($searchQuery, $category);
POST Method Examples:
// HTML Form
<form method="POST" action="process.php">
<input type="text" name="username" required>
<input type="password" name="password" required>
<input type="submit" value="Login">
</form>
// Processing POST data
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$username = filter_input(INPUT_POST, "username", FILTER_SANITIZE_STRING);
$password = $_POST["password"];
// Validate
if (empty($username) || empty($password)) {
$error = "All fields are required";
} else {
// Process login
$user = authenticateUser($username, $password);
}
}
When to Use:
- GET: Search, filtering, pagination, public data retrieval
- POST: Login, registration, file uploads, data modification
Question:
Answer:
You must run command line interface program of PHP and file name of PHP script is given as the command line argument.
Question:
Answer:
In general, there is much difference between procedure oriented and object oriented languages
- It is very difficult to use design patterns such as singleton pattern, MVC etc in procedure oriented language whereas in object oriented programming language it is very easy to develop design patterns.
- In OOP languages the code can be reused using polymorphism and inheritance but it is not possible in procedure oriented language.
- A new developer feels procedure oriented is easy but understanding whole software is complex when compared to object oriented model.
Question:
What is the maximum length of a table name, database name, and fieldname in mysql?
Answer:
Database name- 64
Table name -64
Fieldname-64
Question:
What is maximum size of a database in mysql?
Answer:
The effective maximum table size for MySQL databases is usually determined by operating system constraints on file sizes, not by MySQL internal limits. The following table lists some examples of operating system file-size limits. This is only a rough guide and is not intended to be definitive. For the most up-to-date information, be sure to check the documentation specific to your operating system.
Operating System File-size Limit
Win32 w/ FAT/FAT32 2GB/4GB
Win32 w/ NTFS 2TB (possibly larger)
Linux 2.2-Intel 32-bit 2GB (LFS: 4GB)
Linux 2.4+ (using ext3 file system) 4TB
Solaris 9/10 16TB
Mac OS X w/ HFS+ 2TB
Question:
What is the difference between JavaScript and PHP?
Answer:
The difference lies with the execution of the languages. PHP is server side scripting language, which
means that it can’t interact directly with the user. Whereas, JavaScript is client side scripting
language, that is used to interact directly with the user..
Question:
Why PHP is also called Scripting language?
Answer:
PHP is basically a general purpose language, which is used to write scripts. Scripts are normal computer files that consist of instructions written in PHP language. It tells the computer to execute the file and give the output on the screen.
PHP is used for webpages and to create websites, thus included as scripting language.
Question:
How to use HTTP Headers inside PHP?
Answer:
HTTP headers can be used in PHP by redirection which is written as:
<?header('Location: http://www.php.com')?> The headers can be added to HTTP response in PHP using the header(). The HTTP headers have to be sent before taking the output of any data. The statement above gets included at the top of the script.
Question:
What is meant by MIME?
Answer:
Multipurpose Internet Mail Extensions.
WWW ability to recognise and handle files of different types is largely dependent on the use of the MIME (Multipurpose Internet Mail Extensions) standard. The standard provides for a system of registration of file types with information about the applications needed to process them. This information is incorporated into Web server and browser software, and enables the automatic recognition and display of registered file types.
Question:
Answer:
Question:
Answer:
Question:
Answer:
Question:
Answer:
Question:
Answer:
Question:
What is the difference between include and require?
Answer:
include: Includes a file, continues execution if file not found (warning).\ninclude_once: Same as include but includes file only once.\nrequire: Includes a file, stops execution if file not found (fatal error).\nrequire_once: Same as require but includes file only once.\n\nUse require/require_once for critical files (like config files).\nUse include/include_once for optional files (like templates).\n\nExample:\nrequire_once 'config.php'; // Critical file\ninclude 'header.php'; // Optional template
Question:
What are PHP traits?
Answer:
Traits are a mechanism for code reuse in PHP. They allow you to include methods in multiple classes without using inheritance.\n\nExample:\ntrait Logger {\n public function log($message) {\n echo "Log: $message";\n }\n}\n\nclass User {\n use Logger;\n}\n\nclass Product {\n use Logger;\n}\n\n$user = new User();\n$user->log("User created"); // Works!\n\nTraits solve the problem of multiple inheritance and promote code reuse.
Question:
What is dependency injection?
Answer:
Dependency injection is a design pattern where dependencies are provided to a class rather than the class creating them itself.\n\nBenefits:\n- Loose coupling\n- Easier testing\n- Better maintainability\n- Follows SOLID principles\n\nExample:\nclass EmailService {\n public function send($message) { /* ... */ }\n}\n\nclass UserController {\n private $emailService;\n \n public function __construct(EmailService $emailService) {\n $this->emailService = $emailService;\n }\n}\n\n// Dependency is injected\n$controller = new UserController(new EmailService());
Question:
What is the difference between public, private, and protected?
Answer:
public: Accessible from anywhere\nprivate: Only accessible within the same class\nprotected: Accessible within the class and its subclasses\n\nExample:\nclass MyClass {\n public $publicVar = "Everyone can see this";\n private $privateVar = "Only MyClass can see this";\n protected $protectedVar = "MyClass and subclasses can see this";\n}\n\nclass ChildClass extends MyClass {\n public function test() {\n echo $this->publicVar; // OK\n echo $this->protectedVar; // OK\n echo $this->privateVar; // Error!\n }\n}
Question:
Answer:
The major advantage of object oriented programming is code reuseability and easy of modification. Modification and adding of objects is easy thereby reducing the maintenance cost. Modeling the real world is better using object oriented programming than procedure-oriented programming.
Question:
What is Composer and how does it work?
Answer:
Composer is a dependency manager for PHP. It allows you to declare libraries your project depends on and manages them for you.\n\nKey files:\n- composer.json: Defines dependencies\n- composer.lock: Locks specific versions\n- vendor/: Contains downloaded packages\n\nBasic commands:\ncomposer install // Install dependencies\ncomposer update // Update dependencies\ncomposer require vendor/package // Add new dependency\n\nAutoloading:\nrequire_once "vendor/autoload.php";\n\nBenefits: Version management, autoloading, easy package installation.
Question:
How can we increase the execution time of a php script?
Answer:
Set max_execution_time variable in php.ini file to your desired time in second.
Question:
How do you make one way encryption for your passwords in PHP?
Answer:
Using md5 function or sha1 function
Question:
What is difference between mysql_connect and mysql_pconnect ?
Answer:
Mysql_connect opens up a database connection every time a page is loaded. mysql_pconnect opens up a connection, and keeps it open across multiple requests.
Mysql_pconnect uses less resources, because it does not need to establish a database connection every time a page is loaded.
Question:
What are the statements that are used to connect PHP files with MySQL
Answer:
The statements that can be used to connect PHP with MySQL are:
<?
$con = mysql_connect("localhost","root","")
echo $conn;
?>
This statement gets the resource of the localhost.
Question:
How can we submit a form without a submit button?
Answer:
Forms can be submitted without a submit button using JavaScript.
JavaScript Methods:
// Method 1: Using form.submit()
<form id="myForm" action="process.php" method="POST">
<input type="text" name="username">
<button type="button" onclick="submitForm()">Submit</button>
</form>
<script>
function submitForm() {
document.getElementById("myForm").submit();
}
</script>
// Method 2: Auto-submit on change
<form id="autoForm" action="filter.php" method="GET">
<select name="category" onchange="this.form.submit()">
<option value="all">All Categories</option>
<option value="php">PHP</option>
<option value="javascript">JavaScript</option>
</select>
</form>
Advanced JavaScript Submission:
// Method 3: Using AJAX
function submitFormAjax() {
const form = document.getElementById("myForm");
const formData = new FormData(form);
fetch("process.php", {
method: "POST",
body: formData
})
.then(response => response.json())
.then(data => {
console.log("Success:", data);
// Handle response
})
.catch(error => {
console.error("Error:", error);
});
}
// Method 4: Programmatic form creation and submission
function createAndSubmitForm(data) {
const form = document.createElement("form");
form.method = "POST";
form.action = "process.php";
for (const key in data) {
const input = document.createElement("input");
input.type = "hidden";
input.name = key;
input.value = data[key];
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
Event-Based Submission:
// Submit on Enter key
<input type="text" onkeypress="if(event.key==='Enter') document.forms[0].submit()">
// Submit after timer
setTimeout(() => {
document.getElementById("timedForm").submit();
}, 5000); // Submit after 5 seconds
// Submit on page unload
window.addEventListener("beforeunload", () => {
document.getElementById("trackingForm").submit();
});
Security Considerations: Always validate and sanitize data on the server side, regardless of client-side submission method.
Question:
Answer:
PHP 8.3 introduces several significant features:
1. Typed Class Constants:
You can now specify types for class constants, improving type safety:
class MyClass {
public const string NAME = "MyClass";
public const int VERSION = 1;
public const array CONFIG = ["debug" => true];
}
2. Dynamic Class Constant Fetch:
Allows fetching class constants dynamically using variables:
class Status {
const ACTIVE = "active";
const INACTIVE = "inactive";
}
$constantName = "ACTIVE";
$value = Status::{$constantName}; // Returns "active"
3. Readonly Amendments:
- Readonly properties can now be reinitialized during cloning
- Better support for readonly properties in inheritance
- Improved readonly class behavior
Benefits: Enhanced type safety, better performance, improved developer experience, and more robust object-oriented programming capabilities.
Question:
Answer:
PHP Fibers (introduced in PHP 8.1) enable cooperative multitasking:
Implementation:
$fiber = new Fiber(function (): void {
$value = Fiber::suspend("Hello");
echo "Fiber resumed with: " . $value;
});
$result = $fiber->start(); // "Hello"
echo $result;
$fiber->resume("World"); // Outputs: "Fiber resumed with: World"
Use Cases:
- Asynchronous I/O operations
- Non-blocking database queries
- Concurrent HTTP requests
- Event-driven programming
- Implementing async/await patterns
Comparison with Threading:
- Fibers: Cooperative, single-threaded, no race conditions, lower memory overhead
- Threads: Preemptive, multi-threaded, potential race conditions, higher overhead
- Fibers: Explicit suspension points, deterministic execution
- Threads: OS-controlled scheduling, non-deterministic
Advantages: Better performance for I/O-bound operations, easier debugging, no need for locks or synchronization primitives.
Question:
Answer:
Advanced PHP Design Patterns:
1. Repository Pattern:
Encapsulates data access logic and provides a uniform interface:
interface UserRepositoryInterface {
public function find(int $id): ?User;
public function save(User $user): void;
public function findByEmail(string $email): ?User;
}
class DatabaseUserRepository implements UserRepositoryInterface {
public function find(int $id): ?User {
// Database query logic
return $this->db->query("SELECT * FROM users WHERE id = ?", [$id]);
}
public function save(User $user): void {
// Save logic
}
}
2. Specification Pattern:
Encapsulates business rules and query logic:
interface SpecificationInterface {
public function isSatisfiedBy($candidate): bool;
public function toSql(): string;
}
class ActiveUserSpecification implements SpecificationInterface {
public function isSatisfiedBy($user): bool {
return $user->isActive() && $user->getLastLogin() > new DateTime("-30 days");
}
public function toSql(): string {
return "status = 'active' AND last_login > DATE_SUB(NOW(), INTERVAL 30 DAY)";
}
}
3. CQRS (Command Query Responsibility Segregation):
Separates read and write operations:
// Command side
class CreateUserCommand {
public function __construct(
public readonly string $email,
public readonly string $name
) {}
}
class CreateUserHandler {
public function handle(CreateUserCommand $command): void {
$user = new User($command->email, $command->name);
$this->userRepository->save($user);
}
}
// Query side
class UserQuery {
public function getUserById(int $id): UserReadModel {
return $this->readModelRepository->find($id);
}
}
When to Use:
- Repository: Complex data access, testing, multiple data sources
- Specification: Complex business rules, dynamic queries, reusable conditions
- CQRS: High-performance applications, different read/write requirements, event sourcing
Question:
Answer:
PHP Performance Optimization for 2025:
1. OPcache Configuration:
; php.ini optimizations
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; Production only
opcache.save_comments=0
opcache.enable_file_override=1
opcache.huge_code_pages=1 ; Linux only
2. JIT (Just-In-Time) Compilation:
; Enable JIT in PHP 8.0+
opcache.jit_buffer_size=256M
opcache.jit=tracing ; or "function" for function-level JIT
// Code optimization for JIT
function calculateFibonacci(int $n): int {
if ($n <= 1) return $n;
return calculateFibonacci($n - 1) + calculateFibonacci($n - 2);
}
3. Memory Management Strategies:
- Object Pooling: Reuse expensive objects
- Lazy Loading: Load data only when needed
- Memory Profiling: Use Xdebug or Blackfire
- Garbage Collection: Optimize gc_collect_cycles()
4. Advanced Techniques:
// Use generators for memory efficiency
function readLargeFile(string $filename): Generator {
$handle = fopen($filename, "r");
while (($line = fgets($handle)) !== false) {
yield trim($line);
}
fclose($handle);
}
// Implement object caching
class CachedUserService {
private array $cache = [];
public function getUser(int $id): User {
return $this->cache[$id] ??= $this->userRepository->find($id);
}
}
5. Database Optimization:
- Connection pooling with persistent connections
- Query optimization and indexing
- Database result caching
- Read/write splitting
Monitoring: Use APM tools like New Relic, Datadog, or open-source alternatives like Jaeger for distributed tracing.
Question:
Answer:
Modern PHP Security Practices for 2025:
1. Input Validation & Sanitization:
// Use filter_var with strict validation
function validateEmail(string $email): bool {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
// Input sanitization
function sanitizeInput(string $input): string {
return htmlspecialchars(trim($input), ENT_QUOTES, "UTF-8");
}
// Type declarations for strict typing
declare(strict_types=1);
function processUserData(int $userId, string $email): void {
// Type safety enforced at runtime
}
2. CSRF Protection:
class CSRFProtection {
public static function generateToken(): string {
if (!isset($_SESSION["csrf_token"])) {
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
}
return $_SESSION["csrf_token"];
}
public static function validateToken(string $token): bool {
return isset($_SESSION["csrf_token"]) &&
hash_equals($_SESSION["csrf_token"], $token);
}
}
3. SQL Injection Prevention:
// Use prepared statements exclusively
class UserRepository {
public function findByEmail(string $email): ?User {
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE email = ? AND status = ?");
$stmt->execute([$email, "active"]);
return $stmt->fetchObject(User::class) ?: null;
}
// For dynamic queries, use query builders
public function findWithFilters(array $filters): array {
$queryBuilder = new QueryBuilder();
return $queryBuilder->select("*")
->from("users")
->where($filters) // Automatically parameterized
->execute();
}
}
4. Secure Session Management:
// Secure session configuration
ini_set("session.cookie_httponly", 1);
ini_set("session.cookie_secure", 1);
ini_set("session.cookie_samesite", "Strict");
ini_set("session.use_strict_mode", 1);
ini_set("session.gc_maxlifetime", 3600);
class SecureSession {
public static function start(): void {
session_start();
// Regenerate session ID periodically
if (!isset($_SESSION["last_regeneration"])) {
self::regenerateId();
} elseif (time() - $_SESSION["last_regeneration"] > 300) {
self::regenerateId();
}
}
private static function regenerateId(): void {
session_regenerate_id(true);
$_SESSION["last_regeneration"] = time();
}
}
5. Additional Security Measures:
- Content Security Policy: Implement strict CSP headers
- Rate Limiting: Prevent brute force attacks
- Password Hashing: Use password_hash() with strong algorithms
- HTTPS Enforcement: Redirect all traffic to HTTPS
- Security Headers: X-Frame-Options, X-XSS-Protection, etc.
6. Modern Authentication:
// JWT implementation with proper validation
class JWTAuth {
public function createToken(User $user): string {
$payload = [
"sub" => $user->getId(),
"iat" => time(),
"exp" => time() + 3600,
"aud" => "your-app.com"
];
return JWT::encode($payload, $this->secretKey, "HS256");
}
}Question:
Answer:
Code Analysis:
$value = "2";
$result = match($value) {
1 => "one",
2 => "two",
"2" => "string two",
default => "unknown"
};
echo $result;
Output: "two"
Explanation:
- Match expressions use strict comparison (===) by default
- Since $value is string "2", it matches the first case where 2 (integer) is compared
- However, match does type coercion for the first matching case
- The string "2" matches integer 2, so "two" is returned
- If we had strict types enabled, this would behave differently
Key Difference from Switch: Match is exhaustive and uses strict comparison, but still allows type coercion in pattern matching.
Question:
Answer:
Code Analysis:
function processLargeDataset($filename) {
$data = file_get_contents($filename); // 100MB file
$lines = explode("\n", $data);
$results = [];
foreach($lines as $line) {
$processed = expensive_operation($line);
$results[] = $processed;
}
return $results;
}
Memory Issues:
- Memory Spike: file_get_contents() loads entire file into memory
- Double Memory Usage: explode() creates another copy of data
- Array Growth: $results array grows continuously
- Peak Usage: Could reach 300MB+ for 100MB file
Optimized Solution:
function processLargeDatasetOptimized($filename): Generator {
$handle = fopen($filename, "r");
if (!$handle) throw new Exception("Cannot open file");
try {
while (($line = fgets($handle)) !== false) {
yield expensive_operation(trim($line));
}
} finally {
fclose($handle);
}
}
// Usage with memory control
foreach(processLargeDatasetOptimized($filename) as $result) {
// Process one result at a time
// Memory usage remains constant
}
Benefits: Constant memory usage, lazy evaluation, better performance for large datasets.
Question:
Answer:
PHP Attributes (PHP 8.0+):
Practical Example - API Route Mapping:
#[Attribute(Attribute::TARGET_METHOD)]
class Route {
public function __construct(
public string $method,
public string $path,
public array $middleware = []
) {}
}
#[Attribute(Attribute::TARGET_PARAMETER)]
class Validate {
public function __construct(public string $rules) {}
}
class UserController {
#[Route("POST", "/users", ["auth", "throttle"])]
public function create(
#[Validate("required|email")] string $email,
#[Validate("required|min:8")] string $password
): User {
return User::create(compact("email", "password"));
}
}
// Attribute Processing
class RouteProcessor {
public function processController(string $className): array {
$reflection = new ReflectionClass($className);
$routes = [];
foreach($reflection->getMethods() as $method) {
$attributes = $method->getAttributes(Route::class);
foreach($attributes as $attribute) {
$route = $attribute->newInstance();
$routes[] = [
"method" => $route->method,
"path" => $route->path,
"handler" => [$className, $method->getName()],
"middleware" => $route->middleware
];
}
}
return $routes;
}
}
Differences from Annotations:
- Native Support: Built into PHP, no parsing needed
- Type Safety: Attributes are actual PHP classes
- Performance: Compiled into opcache, faster than docblock parsing
- IDE Support: Full autocompletion and refactoring
Performance Implications:
- Compile Time: Minimal overhead, cached in opcache
- Runtime: Only accessed via Reflection API when needed
- Memory: Stored efficiently in opcache metadata
Question:
Answer:
Code Analysis:
$a = ["x" => 1, "y" => 2];
$b = &$a;
$c = $a;
$a["x"] = 10;
$c["y"] = 20;
unset($a);
var_dump($b);
var_dump($c);
Output:
array(2) {
["x"]=> int(10)
["y"]=> int(2)
}
array(2) {
["x"]=> int(1)
["y"]=> int(20)
}
Explanation:
- $b = &$a: $b becomes a reference to $a (same memory location)
- $c = $a: $c gets a copy of $a (copy-on-write)
- $a["x"] = 10: Modifies original array, affects both $a and $b
- $c["y"] = 20: Triggers copy-on-write, $c becomes independent
- unset($a): Removes $a variable, but $b still references the data
Memory Management:
- Copy-on-Write: PHP optimizes memory by sharing data until modification
- Reference Counting: Memory freed when all references are removed
- Zval Structure: Each variable has reference count and type information
Best Practices:
- Use references sparingly to avoid confusion
- Understand copy-on-write behavior for large arrays
- Use unset() to free memory when working with large datasets
Question:
Answer:
Thread-Safe Singleton Implementation:
final class DatabaseConnection {
private static ?self $instance = null;
private static object $lock;
private PDO $connection;
private function __construct() {
// Initialize lock object for thread safety
if (!isset(self::$lock)) {
self::$lock = new stdClass();
}
$this->connection = new PDO(
"mysql:host=localhost;dbname=app",
"user", "password",
[PDO::ATTR_PERSISTENT => true]
);
}
public static function getInstance(): self {
if (self::$instance === null) {
// Double-checked locking pattern
synchronized(self::$lock, function() {
if (self::$instance === null) {
self::$instance = new self();
}
});
}
return self::$instance;
}
public function getConnection(): PDO {
return $this->connection;
}
// Prevent cloning and unserialization
private function __clone() {}
private function __wakeup() {}
public function __serialize(): array {
throw new Exception("Singleton cannot be serialized");
}
}
Modern Alternative - Dependency Injection:
// Service Container Approach
class Container {
private array $services = [];
private array $singletons = [];
public function singleton(string $abstract, callable $factory): void {
$this->services[$abstract] = $factory;
$this->singletons[$abstract] = true;
}
public function get(string $abstract): mixed {
if (isset($this->singletons[$abstract])) {
static $instances = [];
return $instances[$abstract] ??= $this->services[$abstract]();
}
return $this->services[$abstract]();
}
}
// Usage
$container = new Container();
$container->singleton(DatabaseConnection::class, fn() => new DatabaseConnection());
// Thread-safe through container
$db = $container->get(DatabaseConnection::class);
Challenges with Singleton:
- Testing: Difficult to mock and test
- Thread Safety: Requires synchronization in multi-threaded environments
- Global State: Creates hidden dependencies
- Scalability: Can become bottleneck in high-concurrency applications
Better Alternatives:
- Dependency Injection: More testable and flexible
- Service Locator: Centralized service management
- Factory Pattern: Better control over object creation
- Connection Pooling: For database connections specifically
Question:
Answer:
PHP Garbage Collection Mechanism:
Reference Counting + Cycle Collection:
// Example of circular reference
class Node {
public $data;
public $parent;
public $children = [];
public function addChild(Node $child): void {
$this->children[] = $child;
$child->parent = $this; // Creates circular reference
}
}
$root = new Node();
$child = new Node();
$root->addChild($child); // Circular reference created
// Without proper cleanup, this creates memory leak
unset($root, $child); // Variables removed but objects still referenced
How PHP Handles This:
- Reference Counting: Each zval has refcount
- Cycle Detection: When refcount decreases, check for cycles
- Mark & Sweep: Mark reachable objects, sweep unreachable ones
Garbage Collection Process:
// Manual GC control
gc_enable(); // Enable garbage collection
gc_collect_cycles(); // Force garbage collection
gc_disable(); // Disable garbage collection
// Monitor GC performance
$before = gc_status();
// ... your code ...
$after = gc_status();
echo "Cycles collected: " . ($after["collected"] - $before["collected"]);
echo "Memory freed: " . ($before["memory"] - $after["memory"]) . " bytes";
Performance Implications:
- CPU Overhead: GC runs periodically, can cause pauses
- Memory Overhead: Additional metadata for cycle detection
- Threshold Based: GC triggers when root buffer fills (10,000 items)
Optimization Strategies:
// 1. Explicit cleanup for circular references
class Node {
public function cleanup(): void {
foreach($this->children as $child) {
$child->parent = null;
$child->cleanup();
}
$this->children = [];
}
}
// 2. Weak references (PHP 7.4+)
class Parent {
private WeakMap $children;
public function __construct() {
$this->children = new WeakMap();
}
public function addChild(Child $child): void {
$this->children[$child] = true;
// No strong reference, no circular dependency
}
}
// 3. Use SplObjectStorage for object collections
$storage = new SplObjectStorage();
$storage->attach($object); // Weak reference-like behavior
Best Practices:
- Avoid circular references when possible
- Use weak references for parent-child relationships
- Monitor memory usage in long-running processes
- Consider manual gc_collect_cycles() in memory-intensive operations
Question:
Answer:
Code Analysis:
$multiplier = 10;
$calculator = new class($multiplier) {
private $factor;
public function __construct($factor) {
$this->factor = $factor;
}
public function createMultiplier() {
return function($value) {
return $value * $this->factor;
};
}
public function createStaticMultiplier() {
$factor = $this->factor;
return static function($value) use ($factor) {
return $value * $factor;
};
}
};
$multiply1 = $calculator->createMultiplier();
$multiply2 = $calculator->createStaticMultiplier();
echo $multiply1(5) . "\n";
echo $multiply2(5) . "\n";
// Serialize test
try {
serialize($multiply1);
echo "multiply1 serializable\n";
} catch (Exception $e) {
echo "multiply1 not serializable\n";
}
try {
serialize($multiply2);
echo "multiply2 serializable\n";
} catch (Exception $e) {
echo "multiply2 not serializable\n";
}
Output:
50
50
multiply1 not serializable
multiply2 serializable
Explanation:
1. Anonymous Class Behavior:
- Anonymous class captures $multiplier in constructor
- Creates instance with private $factor = 10
- Class has unique generated name like class@anonymous
2. Closure Binding:
- createMultiplier(): Returns non-static closure bound to $this
- createStaticMultiplier(): Returns static closure with captured variable
- Both access the same value but through different mechanisms
3. Serialization Behavior:
- $multiply1: Cannot serialize - bound to object instance
- $multiply2: Can serialize - static closure with captured variables
Advanced Closure Concepts:
// Closure binding manipulation
$closure = function() {
return $this->factor;
};
// Bind to different object
$boundClosure = $closure->bindTo($calculator, $calculator);
echo $boundClosure(); // 10
// Static binding
$staticClosure = Closure::bind($closure, null, get_class($calculator));
// $staticClosure(); // Error: $this not available in static context
Performance Considerations:
- Object-bound closures keep object in memory
- Static closures are more memory efficient
- Use static closures when $this is not needed