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\nprint "Hello"; // returns 1
var_dump("1" == 1); // bool(true)\nvar_dump("1" === 1); // bool(false)\nvar_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\n$_SESSION["user_id"] = 42;\n$_SESSION["username"] = "Alice";\n\n// Destroy session\nsession_destroy();\nunset($_SESSION);
// Cookie\nsetcookie("username", "Alice", time() + 86400, "/"); // 1 day\necho $_COOKIE["username"];\n\n// Session\nsession_start();\n$_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);\n$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n\n$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");\n$stmt->execute(["email" => $email]);\n$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\n$sql = "SELECT * FROM users WHERE id = " . $_GET["id"];\n\n// Safe with prepared statement\n$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");\n$stmt->execute([$_GET["id"]]);
abstract class Animal {\n abstract public function speak(): string;\n public function breathe(): void { echo "breathing"; }\n}\n\ninterface Swimmable {\n public function swim(): void;\n}
class Counter {\n private static int $count = 0;\n public static function increment(): void { self::$count++; }\n public static function getCount(): int { return self::$count; }\n}\nCounter::increment();\necho Counter::getCount(); // 1
class Base {\n public static function create(): static { return new static(); } // late static binding\n}\nclass Child extends Base {}\n$obj = Child::create(); // returns Child instance, not Base
trait Timestampable {\n public function getCreatedAt(): string { return $this->created_at; }\n public function touch(): void { $this->updated_at = date("Y-m-d H:i:s"); }\n}\n\nclass User {\n use Timestampable;\n}
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 {\n return compact("name", "age", "role");\n}\n\n// Named arguments - skip age, set role\ncreateUser(name: "Alice", role: "admin");
Union types allow a parameter or return type to accept multiple types.
function processInput(int|string $input): int|string {\n return is_int($input) ? $input * 2 : strtoupper($input);\n}\n\nprocessInput(5); // 10\nprocessInput("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;\n$label = match($status) {\n 1 => "Active",\n 2, 3 => "Pending",\n 4 => "Inactive",\n default => "Unknown"\n};\n// 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\n$city = null;\nif ($user !== null && $user->getAddress() !== null) {\n $city = $user->getAddress()->getCity();\n}\n\n// PHP 8 nullsafe\n$city = $user?->getAddress()?->getCity();
$nums = [1, 2, 3, 4, 5];\narray_map(fn($x) => $x * 2, $nums); // [2,4,6,8,10]\narray_filter($nums, fn($x) => $x % 2); // [1,3,5]\narray_reduce($nums, fn($c, $x) => $c + $x, 0); // 15
$a = [1, 2, "x" => "a"];\n$b = [3, "x" => "b"];\narray_merge($a, $b); // [1, 2, "x"=>"b", 3] - numeric re-indexed\narray_replace($a, $b); // [3, 2, "x"=>"b"] - key 0 replaced
$a = 0;\nvar_dump(isset($a)); // true (exists, not null)\nvar_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];\n\n// list()\nlist($x, $y, $z) = $coords;\n\n// Array destructuring (modern)\n[$x, $y, $z] = $coords;\n\n// With keys\n["name" => $name, "age" => $age] = $user;
$name = "Alice";\n$heredoc = <<<EOT\nHello $name\nEOT; // "Hello Alice"\n\n$nowdoc = <<<'EOT'\nHello $name\nEOT; // "Hello $name" (literal)
$hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 12]);\n\nif (password_verify($inputPassword, $hash)) {\n // authenticated\n}
XSS (Cross-Site Scripting) injects malicious scripts into web pages. Prevent by escaping output with htmlspecialchars() before displaying user input.
// Vulnerable\necho $_GET["name"];\n\n// Safe\necho htmlspecialchars($_GET["name"], ENT_QUOTES, "UTF-8");\n\n// 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\n$_SESSION["csrf_token"] = bin2hex(random_bytes(32));\n\n// In form\necho '<input type="hidden" name="csrf_token" value="' . $_SESSION["csrf_token"] . '">'\n\n// Validate\nif (!hash_equals($_SESSION["csrf_token"], $_POST["csrf_token"])) {\n die("CSRF validation failed");\n}
// Redirect\nheader("Location: /dashboard");\nexit;\n\n// JSON response\nheader("Content-Type: application/json");\necho json_encode($data);
$data = ["name" => "Alice", "age" => 30];\n$json = json_encode($data); // {"name":"Alice","age":30}\n\n$obj = json_decode($json); // stdClass\n$arr = json_decode($json, true); // associative array
// Simple\n$content = file_get_contents("file.txt");\n\n// Chunked reading\n$handle = fopen("large.txt", "r");\nwhile (!feof($handle)) {\n $chunk = fread($handle, 8192);\n}\nfclose($handle);
Constructor property promotion (PHP 8) combines property declaration and constructor assignment into one.
// Traditional\nclass User {\n private string $name;\n private int $age;\n public function __construct(string $name, int $age) {\n $this->name = $name;\n $this->age = $age;\n }\n}\n\n// PHP 8 promotion\nclass User {\n public function __construct(\n private string $name,\n private int $age\n ) {}\n}
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 {\n $value = Fiber::suspend("first");\n echo "Got: $value\n";\n});\n\n$result = $fiber->start(); // "first"\n$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 {\n case Active;\n case Inactive;\n}\n\n// Backed enum\nenum Color: string {\n case Red = "red";\n case Blue = "blue";\n}\n\necho Color::Red->value; // "red"\n$color = Color::from("blue"); // Color::Blue
$arr = ["key" => null];\nvar_dump(array_key_exists("key", $arr)); // true\nvar_dump(isset($arr["key"])); // false (value is null)
$fruits = ["apple", "banana", "cherry"];\nin_array("banana", $fruits); // true\narray_search("banana", $fruits); // 1 (key)
$users = [["name"=>"Bob","age"=>30],["name"=>"Alice","age"=>25]];\nusort($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;\n$multiply = function($x) use ($multiplier) {\n return $x * $multiplier;\n};\necho $multiply(5); // 15\n\n// Arrow function (PHP 7.4) - auto-captures\n$multiply = fn($x) => $x * $multiplier;
$factor = 2;\n$double = fn($x) => $x * $factor; // auto-captures $factor\necho $double(5); // 10
interface LoggerInterface {\n public function log(string $message): void;\n}\n\nclass UserService {\n public function __construct(private LoggerInterface $logger) {}\n}
class User {\n public readonly string $id;\n const VERSION = "1.0";\n public function __construct(string $id) {\n $this->id = $id; // can only be set here\n }\n}
// Array: loads all 1M rows into memory\n$rows = $pdo->query("SELECT * FROM logs")->fetchAll();\n\n// Generator: one tl-row at a time\nfunction getLogs(PDO $pdo): Generator {\n $stmt = $pdo->query("SELECT * FROM logs");\n while ($row = $stmt->fetch()) yield $row;\n}
// Union type\nfunction process(int|string $input): void {}\n\n// Intersection type (PHP 8.1)\nfunction processCollection(Countable&Iterator $collection): void {}
function redirect(string $url): never {\n header("Location: $url");\n exit;\n}\n\nfunction logMessage(): void {\n echo "logged"; // returns normally\n}
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\nusort($arr, ["MyClass", "compare"]);\narray_map("strtoupper", $strings);\n\n// First class callable (PHP 8.1)\nusort($arr, MyClass::compare(...));\narray_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)\nfunction process((Countable&Iterator)|array $input): void {\n // accepts: object implementing both Countable and Iterator, OR an array\n}
PHP 8 introduced three readable string helper functions replacing strpos() hacks.
$str = "Hello World";\nstr_contains($str, "World"); // true\nstr_starts_with($str, "Hello"); // true\nstr_ends_with($str, "World"); // true\n\n// Before PHP 8\nstrpos($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\n$value = $input ?? throw new InvalidArgumentException("Required");\n$name = fn($x) => $x ?: throw new ValueError("Empty");\n\n// Traditional (PHP 7)\nif ($input === null) {\n throw new InvalidArgumentException("Required");\n}
Explore 500+ free tutorials across 20+ languages and frameworks.