Curated questions covering OOP, sessions, cookies, database connectivity, security, PHP 8 features, and Laravel framework concepts.
PHP (Hypertext Preprocessor) is a server-side scripting language designed for web development. Key features: embedded in HTML, extensive database support, cross-platform, large ecosystem (Laravel, Symfony, WordPress), and PHP 8 features like JIT compilation, named arguments, and union types.
echo "Hello", " World"; // multiple args
print "Hello"; // returns 1
var_dump("1" == 1); // bool(true)
var_dump("1" === 1); // bool(false)
var_dump(0 == "foo"); // bool(true) in PHP 7, bool(false) in PHP 8
Sessions store user data on the server across multiple pages. PHP assigns a unique session ID (stored in a cookie or URL). Data is stored in $_SESSION superglobal.
session_start(); // must be called before any output
$_SESSION["user_id"] = 42;
$_SESSION["username"] = "Alice";
// Destroy session
session_destroy();
unset($_SESSION);
// Cookie
setcookie("username", "Alice", time() + 86400, "/"); // 1 day
echo $_COOKIE["username"];
// Session
session_start();
$_SESSION["username"] = "Alice";
PDO (PHP Data Objects) is a database abstraction layer providing a consistent interface for multiple databases. It supports prepared statements (preventing SQL injection), multiple database drivers, and named parameters. mysql_ functions are deprecated and removed in PHP 7.
$pdo = new PDO("mysql:host=localhost;dbname=mydb", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
$stmt->execute(["email" => $email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
Prepared statements separate SQL code from data. The query structure is sent to the database first, then data is bound separately. The database treats bound values as data, never as SQL code, preventing injection.
// Vulnerable
$sql = "SELECT * FROM users WHERE id = " . $_GET["id"];
// Safe with prepared statement
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET["id"]]);
abstract class Animal {
abstract public function speak(): string;
public function breathe(): void { echo "breathing"; }
}
interface Swimmable {
public function swim(): void;
}
class Counter {
private static int $count = 0;
public static function increment(): void { self::$count++; }
public static function getCount(): int { return self::$count; }
}
Counter::increment();
echo Counter::getCount(); // 1
class Base {
public static function create(): static { return new static(); } // late static binding
}
class Child extends Base {}
$obj = Child::create(); // returns Child instance, not Base
trait Timestampable {
public function getCreatedAt(): string { return $this->created_at; }
public function touch(): void { $this->updated_at = date("Y-m-d H:i:s"); }
}
class User {
use Timestampable;
}
Named arguments allow passing arguments by parameter name, in any order, and skipping optional parameters.
function createUser(string $name, int $age = 0, string $role = "user"): array {
return compact("name", "age", "role");
}
// Named arguments - skip age, set role
createUser(name: "Alice", role: "admin");
Union types allow a parameter or return type to accept multiple types.
function processInput(int|string $input): int|string {
return is_int($input) ? $input * 2 : strtoupper($input);
}
processInput(5); // 10
processInput("hello"); // "HELLO"
match is a stricter alternative to switch. It uses strict comparison (===), returns a value, does not fall through, and throws UnhandledMatchError for unmatched values.
$status = 2;
$label = match($status) {
1 => "Active",
2, 3 => "Pending",
4 => "Inactive",
default => "Unknown"
};
// No break needed, returns value directly
The nullsafe operator (?->) short-circuits the chain and returns null if any part is null, instead of throwing an error.
// Before PHP 8
$city = null;
if ($user !== null && $user->getAddress() !== null) {
$city = $user->getAddress()->getCity();
}
// PHP 8 nullsafe
$city = $user?->getAddress()?->getCity();
$nums = [1, 2, 3, 4, 5];
array_map(fn($x) => $x * 2, $nums); // [2,4,6,8,10]
array_filter($nums, fn($x) => $x % 2); // [1,3,5]
array_reduce($nums, fn($c, $x) => $c + $x, 0); // 15
$a = [1, 2, "x" => "a"];
$b = [3, "x" => "b"];
array_merge($a, $b); // [1, 2, "x"=>"b", 3] - numeric re-indexed
array_replace($a, $b); // [3, 2, "x"=>"b"] - key 0 replaced
$a = 0;
var_dump(isset($a)); // true (exists, not null)
var_dump(empty($a)); // true (0 is falsy)
Both extract values from arrays. list() is the older syntax; [] destructuring (PHP 7.1+) is the modern equivalent.
$coords = [10, 20, 30];
// list()
list($x, $y, $z) = $coords;
// Array destructuring (modern)
[$x, $y, $z] = $coords;
// With keys
["name" => $name, "age" => $age] = $user;
$name = "Alice";
$heredoc = <<<EOT
Hello $name
EOT; // "Hello Alice"
$nowdoc = <<<'EOT'
Hello $name
EOT; // "Hello $name" (literal)
$hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 12]);
if (password_verify($inputPassword, $hash)) {
// authenticated
}
XSS (Cross-Site Scripting) injects malicious scripts into web pages. Prevent by escaping output with htmlspecialchars() before displaying user input.
// Vulnerable
echo $_GET["name"];
// Safe
echo htmlspecialchars($_GET["name"], ENT_QUOTES, "UTF-8");
// Or use a template engine (Twig auto-escapes by default)
CSRF (Cross-Site Request Forgery) tricks users into submitting requests they did not intend. Prevent with CSRF tokens: generate a unique token per session, include it in forms, and validate on submission.
// Generate token
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
// In form
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION["csrf_token"] . '">'
// Validate
if (!hash_equals($_SESSION["csrf_token"], $_POST["csrf_token"])) {
die("CSRF validation failed");
}
// Redirect
header("Location: /dashboard");
exit;
// JSON response
header("Content-Type: application/json");
echo json_encode($data);
$data = ["name" => "Alice", "age" => 30];
$json = json_encode($data); // {"name":"Alice","age":30}
$obj = json_decode($json); // stdClass
$arr = json_decode($json, true); // associative array
// Simple
$content = file_get_contents("file.txt");
// Chunked reading
$handle = fopen("large.txt", "r");
while (!feof($handle)) {
$chunk = fread($handle, 8192);
}
fclose($handle);
Constructor property promotion (PHP 8) combines property declaration and constructor assignment into one.
// Traditional
class User {
private string $name;
private int $age;
public function __construct(string $name, int $age) {
$this->name = $name;
$this->age = $age;
}
}
// PHP 8 promotion
class User {
public function __construct(
private string $name,
private int $age
) {}
}
Fibers (PHP 8.1) are lightweight cooperative concurrency primitives. A Fiber can be paused with Fiber::suspend() and resumed later. They are the foundation for async PHP frameworks.
$fiber = new Fiber(function(): void {
$value = Fiber::suspend("first");
echo "Got: $value\n";
});
$result = $fiber->start(); // "first"
$fiber->resume("hello"); // "Got: hello"
Enums (PHP 8.1) are a type-safe way to define a set of named constants. Backed enums have string or int values.
enum Status {
case Active;
case Inactive;
}
// Backed enum
enum Color: string {
case Red = "red";
case Blue = "blue";
}
echo Color::Red->value; // "red"
$color = Color::from("blue"); // Color::Blue
$arr = ["key" => null];
var_dump(array_key_exists("key", $arr)); // true
var_dump(isset($arr["key"])); // false (value is null)
$fruits = ["apple", "banana", "cherry"];
in_array("banana", $fruits); // true
array_search("banana", $fruits); // 1 (key)
$users = [["name"=>"Bob","age"=>30],["name"=>"Alice","age"=>25]];
usort($users, fn($a,$b) => $a["age"] <=> $b["age"]);
Closures are anonymous functions that can capture variables from the enclosing scope using use keyword. Regular functions cannot access outer scope variables.
$multiplier = 3;
$multiply = function($x) use ($multiplier) {
return $x * $multiplier;
};
echo $multiply(5); // 15
// Arrow function (PHP 7.4) - auto-captures
$multiply = fn($x) => $x * $multiplier;
$factor = 2;
$double = fn($x) => $x * $factor; // auto-captures $factor
echo $double(5); // 10
interface LoggerInterface {
public function log(string $message): void;
}
class UserService {
public function __construct(private LoggerInterface $logger) {}
}
class User {
public readonly string $id;
const VERSION = "1.0";
public function __construct(string $id) {
$this->id = $id; // can only be set here
}
}
// Array: loads all 1M rows into memory
$rows = $pdo->query("SELECT * FROM logs")->fetchAll();
// Generator: one tl-row at a time
function getLogs(PDO $pdo): Generator {
$stmt = $pdo->query("SELECT * FROM logs");
while ($row = $stmt->fetch()) yield $row;
}
// Union type
function process(int|string $input): void {}
// Intersection type (PHP 8.1)
function processCollection(Countable&Iterator $collection): void {}
function redirect(string $url): never {
header("Location: $url");
exit;
}
function logMessage(): void {
echo "logged"; // returns normally
}
First class callable syntax (PHP 8.1) creates a Closure from any callable using the ... syntax, providing a cleaner alternative to array callbacks and string function names.
// Traditional
usort($arr, ["MyClass", "compare"]);
array_map("strtoupper", $strings);
// First class callable (PHP 8.1)
usort($arr, MyClass::compare(...));
array_map(strtoupper(...), $strings);
DNF (Disjunctive Normal Form) types (PHP 8.2) allow combining union and intersection types: (A&B)|C means "implements both A and B, OR is of type C".
// DNF type (PHP 8.2)
function process((Countable&Iterator)|array $input): void {
// accepts: object implementing both Countable and Iterator, OR an array
}
PHP 8 introduced three readable string helper functions replacing strpos() hacks.
$str = "Hello World";
str_contains($str, "World"); // true
str_starts_with($str, "Hello"); // true
str_ends_with($str, "World"); // true
// Before PHP 8
strpos($str, "World") !== false; // verbose
PHP 8 allows throw to be used as an expression, enabling it in arrow functions, ternary operators, and null coalescing.
// PHP 8 throw as expression
$value = $input ?? throw new InvalidArgumentException("Required");
$name = fn($x) => $x ?: throw new ValueError("Empty");
// Traditional (PHP 7)
if ($input === null) {
throw new InvalidArgumentException("Required");
}
Explore 500+ free tutorials across 20+ languages and frameworks.