PHP Introduction

PHP is a server-side scripting language built specifically for making dynamic, interactive websites. Instead of running in the visitor’s browser like JavaScript, PHP code runs on the web server, generates HTML (or JSON, or anything else), and only the finished output is sent to the browser. It powers an enormous share of the web, from small personal blogs to massive platforms like Facebook and Wikipedia, largely because it’s free, easy to embed directly into HTML, and has a huge ecosystem of frameworks and libraries.

Overview: How PHP Works

PHP stands for “PHP: Hypertext Preprocessor” (a recursive acronym). The key idea behind PHP is that it is a server-side language: when a browser requests a .php file, the web server hands that file to the PHP engine (the Zend Engine, in the reference implementation) instead of sending it straight to the browser. The engine reads the file top to bottom, executes any code between <?php and ?> tags, and passes everything else through untouched. Whatever the PHP code echos or prints gets woven into that untouched HTML, and the combined result — plain HTML, CSS classes, JavaScript, whatever you output — is what gets sent back to the browser. The visitor never sees your PHP source code, only the output it produced.

Under the hood, when a request for a PHP script arrives, roughly four things happen: (1) the server (Apache, Nginx via PHP-FPM, or the built-in dev server) locates the requested .php file, (2) the Zend Engine lexes and parses the file into tokens and then into an abstract syntax tree, (3) that tree is compiled into opcodes (a low-level bytecode), which may be cached by OPcache so future requests skip re-parsing, and (4) the Zend Virtual Machine executes those opcodes line by line, allocating memory for variables, calling functions, and building up output in a buffer. Once the script finishes (or calls exit/die), the accumulated output is flushed to the client and PHP tears down all the memory it used for that request — there’s no persistent state between requests unless you explicitly use something like a session, a cache, or a database.

This “one file in, one response out, then forget everything” execution model is fundamentally different from long-running server processes written in Node.js or Go. It makes PHP simple to reason about (every request starts from a clean slate) and easy to deploy (just drop files on a server), at the cost of needing extra tools (sessions, caching layers, opcode caches) to persist data or improve performance across requests.

PHP is loosely typed, but not typeless

Every value in PHP has a type — int, float, string, bool, array, object, null, and a few others — but variables themselves aren’t locked to a type unless you explicitly declare one. PHP will automatically convert between compatible types when it needs to (this is called type juggling), which is convenient but is also the source of many classic PHP bugs, covered later in this lesson.

Syntax

Every block of PHP code lives inside special tags. The general form of a PHP file that mixes HTML and PHP looks like this:

<!DOCTYPE html>
<html>
<body>

<?php
    // PHP code goes here
    echo "This was generated by PHP";
?>

</body>
</html>
  • <?php ... ?> — opens and closes a block of PHP code. Anything outside these tags is sent to the browser as-is. In pure-PHP files (like classes or API endpoints) the closing ?> is conventionally omitted to avoid accidental whitespace in the output.
  • ; — every PHP statement ends with a semicolon, just like C or Java.
  • $variable — variables always start with a dollar sign, are case-sensitive, and don’t need a declared type ($name, $Name, and $NAME are three different variables).
  • // and # — single-line comments; /* ... */ — multi-line comments.
  • echo / print — output text or values. echo is marginally faster and can take multiple comma-separated arguments; print always returns 1 and can be used inside expressions.

Examples

Example 1: Variables and string interpolation

<?php
$name = "Ava";
$age = 29;
echo "Hello, my name is $name and I am $age years old.\n";
echo "Next year I will be " . ($age + 1) . " years old.\n";

Output:

Hello, my name is Ava and I am 29 years old.
Next year I will be 30 years old.

This example shows two core PHP habits: double-quoted strings automatically interpolate variables ($name and $age are replaced with their values), while the . operator concatenates strings together, which is needed here because ($age + 1) is an expression, not a bare variable, so it can’t be interpolated directly inside the string.

Example 2: Functions, arrays, and match

<?php
function formatPrice(float $amount, string $currency = "USD"): string {
    return match ($currency) {
        "USD" => "$" . number_format($amount, 2),
        "EUR" => number_format($amount, 2) . " \u{20AC}",
        default => number_format($amount, 2) . " " . $currency,
    };
}

$cart = [
    ["item" => "Keyboard", "price" => 49.99],
    ["item" => "Mouse", "price" => 19.5],
    ["item" => "Monitor", "price" => 199.0],
];

$total = 0.0;
foreach ($cart as $product) {
    $total += $product["price"];
    echo $product["item"] . ": " . formatPrice($product["price"]) . "\n";
}

echo "Total: " . formatPrice($total) . "\n";

Output:

Keyboard: $49.99
Mouse: $19.50
Monitor: $199.00
Total: $268.49

Here, formatPrice() is a typed function: it declares that $amount must be a float, $currency defaults to "USD", and the return value is a string. The match expression (PHP 8’s stricter, expression-based alternative to switch) picks a formatting style based on the currency. The $cart variable is an associative array of arrays — PHP’s single, flexible array type covers what other languages split into lists, maps, and dictionaries.

Example 3: Classes with constructor promotion

<?php
class User {
    public function __construct(
        public readonly string $username,
        public readonly ?string $email = null,
    ) {}

    public function greeting(): string {
        return "Welcome, {$this->username}!";
    }
}

$users = [
    new User("cveil", "cveil@example.com"),
    new User("guest"),
];

$greet = fn(User $u) => $u->greeting();

foreach ($users as $user) {
    echo $greet($user) . "\n";
    echo "Email: " . ($user->email ?? "not provided") . "\n";
}

Output:

Welcome, cveil!
Email: cveil@example.com
Welcome, guest!
Email: not provided

This modern example uses constructor property promotion (declaring and assigning $username/$email directly in the constructor signature), readonly properties (they can only be set once), a nullable type ?string, an arrow function (fn(...) => ...) as a short-hand closure, and the null coalescing operator ??, which returns its left side unless that side is null, in which case it returns the right side.

How It Works Step by Step

  • The browser sends an HTTP request for a URL that maps to a .php file (directly, or through a router/front controller).
  • The web server passes the file to the PHP engine instead of serving it as static text.
  • PHP scans the file for <?php ... ?> blocks; everything outside those tags is treated as literal output.
  • The code inside the tags is parsed, compiled to opcodes, and executed top to bottom, in order.
  • Any echo/print statements append to an internal output buffer.
  • When the script ends, PHP sends the accumulated output (HTML, JSON, plain text — whatever was produced) back to the server, which forwards it to the browser as the HTTP response body.
  • All variables, objects, and memory used by that request are discarded; the next request starts completely fresh.

Common Mistakes

Mistake 1: Expecting single quotes to interpolate variables

Single-quoted strings in PHP are treated almost literally — they do not expand variables (with the sole exception of escaping \' and \\).

<?php
$name = "Ava";
echo 'Hello, $name!';

Output:

Hello, $name!

The dollar sign and variable name are printed literally instead of being replaced with "Ava", which surprises many newcomers. Fix it by using double quotes when you want interpolation:

<?php
$name = "Ava";
echo "Hello, $name!";

Mistake 2: Forgetting break in a switch

Without a break, execution “falls through” into the next case, running code you didn’t intend to run.

<?php
$day = 3;
switch ($day) {
    case 1:
        echo "Monday";
    case 2:
        echo "Tuesday";
    case 3:
        echo "Wednesday";
    case 4:
        echo "Thursday";
}

Output:

WednesdayThursday

Because case 3 has no break, control falls straight into case 4 as well. Adding break; after each case (or using a match expression, which never falls through) fixes it:

<?php
$day = 3;
switch ($day) {
    case 1:
        echo "Monday";
        break;
    case 2:
        echo "Tuesday";
        break;
    case 3:
        echo "Wednesday";
        break;
    case 4:
        echo "Thursday";
        break;
}

Output:

Wednesday

Best Practices

  • Always end pure-PHP files (classes, includes, API endpoints) without a closing ?> tag to avoid stray whitespace leaking into your output.
  • Prefer double quotes only when you actually need interpolation; use single quotes for plain literal text — it’s a tiny bit faster and communicates intent.
  • Declare parameter and return types on functions (function foo(int $x): string) so mistakes are caught early instead of silently type-juggled.
  • Turn on error reporting during development (error_reporting(E_ALL) and display_errors = On) so mistakes surface immediately instead of failing silently.
  • Use === and !== (strict comparison) instead of ==/!= unless you specifically want type juggling — it prevents surprising bugs like "0" == false.
  • Keep business logic out of files that mix heavy HTML and PHP; separate “what to compute” from “how to display it” as your scripts grow.

Practice Exercises

  • Exercise 1: Write a script that declares a $temperatureCelsius variable, converts it to Fahrenheit using the formula F = C * 9/5 + 32, and echoes a sentence stating both values.
  • Exercise 2: Write a function describeNumber(int $n): string that uses a match expression to return "negative", "zero", or "positive" depending on the sign of $n, then call it for -5, 0, and 12 and echo each result.
  • Exercise 3: Create an array of three associative arrays representing books (each with title and pages), loop over them with foreach, and echo the title of only the books with more than 300 pages.

Summary

  • PHP is a server-side language: it runs on the web server and sends only the resulting output (usually HTML) to the browser.
  • Code lives inside <?php ... ?> tags; everything else in the file is passed through untouched.
  • Each request is handled independently — PHP builds up state, produces output, then discards everything when the script ends.
  • Variables start with $, are case-sensitive, and don’t require declared types, though modern PHP lets you add types for safety.
  • Double-quoted strings interpolate variables; single-quoted strings do not.
  • Modern PHP (8.x) adds typed properties, readonly properties, constructor promotion, match, arrow functions, and the nullsafe/null-coalescing operators, all of which make code shorter and safer than older PHP.