Senior 6 min · March 06, 2026

PHP Type Juggling — How == Unlocks Any Account

PHP's loose comparison (==) treats 0 == '0' as true, allowing login bypass.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • PHP variables start with $ and can hold any data type without prior declaration
  • Scalar types: string, int, float, bool — each holds one value
  • Arrays: indexed (numbered) or associative (key-value) for multiple values
  • Type juggling: PHP auto-converts types in expressions, which can produce surprising results
  • Performance: loose comparisons (==) cause implicit conversions — always prefer === for speed and correctness
  • Production trap: using == on "0" or empty strings gives wrong boolean logic — use strict equality
Plain-English First

Think of a variable like a labelled box in your bedroom. You write a name on the outside — say 'favourite colour' — and you put something inside, like the word 'blue'. Later, you can open that box, peek inside, change its contents, or use what's in it. PHP variables work exactly the same way: you give the box a name starting with a dollar sign ($), and you put a value inside it. Data types are just the category of thing you're storing — words go in one kind of box, numbers in another, true/false answers in another.

Every website you've ever used stores and moves information around — your username, the price of a product, whether you're logged in or not. PHP is the language running behind the scenes on millions of web servers doing exactly that work. To do any of it, PHP needs a way to hold pieces of information temporarily while it processes them. That's where variables come in. Without them, you couldn't build a login page, a shopping cart, or even a simple 'Hello, [your name]!' greeting.

The problem variables solve is simple: you don't always know the exact value you'll be working with when you write your code. A user's name could be 'Alice' or 'Zhang Wei' or anything in between. Rather than hardcoding a specific value, you use a variable as a placeholder — a named slot that holds whatever value arrives at runtime. Data types tell PHP what kind of value is sitting in that slot, which determines what operations are valid. You can multiply two numbers, but you can't multiply two names — and PHP needs to know the difference.

By the end of this article you'll be able to declare PHP variables with confidence, understand why PHP has eight built-in data types and when each one is appropriate, read and write real PHP code that stores and outputs meaningful data, and spot the beginner mistakes that trip up even developers who've been coding for a while. Let's build this knowledge from the ground up.

Declaring PHP Variables — The Dollar Sign Rule and Naming Your Boxes

In PHP, every variable starts with a dollar sign ($). That's not optional — it's how PHP recognises 'this is a variable, not a keyword or a function name'. Immediately after the dollar sign comes your chosen name. You assign a value using a single equals sign (=), which in programming is called the assignment operator — it doesn't mean 'equal to', it means 'put this value into this box'.

Naming rules matter. Variable names must start with a letter or an underscore, never a number. They're case-sensitive, so $userAge and $userage are two completely different variables — a common source of bugs. Use descriptive names. $a means nothing to the next developer (or future you). $customerAge, $orderTotal, and $isLoggedIn all tell a story at a glance.

PHP is a loosely typed language, which means you don't have to declare what type of data a variable will hold before you use it. You just assign a value and PHP figures out the type automatically. This is very beginner-friendly, but it comes with traps we'll cover in the gotchas section. For now, know that PHP's flexibility is a feature — used carefully.

variable_basics.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

// Declaring a string variable — text always goes inside quotes
$customerName = "Maria Santos";

// Declaring an integer variable — whole numbers, no quotes needed
$customerAge = 28;

// Declaring a float variable — numbers with decimal points
$accountBalance = 1042.75;

// Declaring a boolean variable — only two possible values: true or false
$isSubscribed = true;

// Outputting variables using echo
// The dot (.) is PHP's string concatenation operator — it joins strings together
echo "Customer: " . $customerName . "\n";   // Prints the customer's name
echo "Age: " . $customerAge . "\n";          // Prints the age as text
echo "Balance: $" . $accountBalance . "\n";  // Prints the balance
echo "Subscribed: ";                          // Starts the subscribed line
echo $isSubscribed ? "Yes" : "No";           // Ternary: prints Yes if true, No if false
echo "\n";

// PHP also lets you embed variables directly inside double-quoted strings
// This is called variable interpolation — PHP replaces the variable with its value
echo "Hello, $customerName! Your balance is $$accountBalance.\n";

// Checking what type PHP assigned using gettype()
echo "Type of customerAge: " . gettype($customerAge) . "\n";     // integer
echo "Type of accountBalance: " . gettype($accountBalance) . "\n"; // double (PHP calls floats 'double')
echo "Type of customerName: " . gettype($customerName) . "\n";   // string

?>
Output
Customer: Maria Santos
Age: 28
Balance: $1042.75
Subscribed: Yes
Hello, Maria Santos! Your balance is $1042.75.
Type of customerAge: integer
Type of accountBalance: double
Type of customerName: string
Pro Tip:
Use var_dump() instead of echo when debugging — it shows both the value AND the data type in one shot. Try var_dump($customerAge) and you'll see int(28), which confirms exactly what PHP is storing. It's your best friend when a variable isn't behaving as expected.
Production Insight
In production, variable naming directly impacts debugging speed.
A single-character variable like $x hides bugs that cost hours to find.
Rule: name variables as if the next person reading your code knows where you live.
Key Takeaway
Every PHP variable starts with $ and must begin with a letter or underscore.
Use descriptive names to make your code self-documenting.
PHP figures out types automatically — that's convenience, not a license to ignore type awareness.

PHP's Eight Data Types — What Can You Actually Store?

PHP has eight built-in data types, split into three families. Scalar types hold a single value: strings (text), integers (whole numbers), floats (decimal numbers), and booleans (true/false). Compound types hold multiple values: arrays (ordered lists or key-value maps) and objects (custom structured data). Special types cover two edge cases: NULL (a variable that deliberately holds nothing) and resource (a reference to an external resource like a database connection).

As a beginner you'll spend 90% of your time with the four scalar types and arrays. Objects come into play when you learn object-oriented PHP later. NULL is more common than you'd think — it's the default state of a variable that's been declared but not assigned, and it's also useful for signalling 'no result found'.

Arrays deserve special attention because they're incredibly powerful. An indexed array works like a numbered list — items are stored at positions 0, 1, 2 and so on. An associative array works like a dictionary — each item has a named key ('email', 'age', 'city') that you use to look it up. You'll use arrays constantly in real PHP work: storing database results, handling form submissions, building configuration settings.

data_types_overview.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php

// ── SCALAR TYPES ──────────────────────────────────────────────

// STRING — any text wrapped in quotes
$productName = "Wireless Noise-Cancelling Headphones";

// INTEGER — whole numbers, positive or negative, no decimal point
$stockCount = 142;
$temperatureInCelsius = -5; // Integers can be negative

// FLOAT (also called double) — numbers with a decimal point
$productPrice = 89.99;
$taxRate = 0.08; // 8% tax stored as a decimal

// BOOLEAN — exactly two possible values: true or false (lowercase in PHP)
$isInStock = true;
$isDiscounted = false;

// ── COMPOUND TYPES ────────────────────────────────────────────

// INDEXED ARRAY — like a numbered shopping list, positions start at 0
$shoppingCart = ["Headphones", "Phone Case", "USB Cable"];

// ASSOCIATIVE ARRAY — like a form with labelled fields
$customerProfile = [
    "firstName"  => "James",      // key => value
    "lastName"   => "Okonkwo",
    "email"      => "james@example.com",
    "age"        => 34
];

// ── SPECIAL TYPES ─────────────────────────────────────────────

// NULL — the absence of a value; this variable exists but holds nothing
$discountCode = null;

// ── USING THE DATA ────────────────────────────────────────────

// Calculate final price with tax
$finalPrice = $productPrice + ($productPrice * $taxRate); // float arithmetic

echo "Product: $productName\n";
echo "Price: $" . number_format($finalPrice, 2) . "\n"; // number_format rounds to 2 decimal places
echo "In stock: " . ($isInStock ? "Yes" : "No") . "\n";
echo "Stock count: $stockCount units\n\n";

// Accessing an indexed array by position number
echo "First cart item: " . $shoppingCart[0] . "\n"; // Index 0 = first item
echo "Second cart item: " . $shoppingCart[1] . "\n";

// Accessing an associative array by key name
echo "Customer: " . $customerProfile["firstName"] . " " . $customerProfile["lastName"] . "\n";
echo "Email: " . $customerProfile["email"] . "\n";

// Checking for NULL with is_null()
if (is_null($discountCode)) {
    echo "No discount code applied.\n";
}

// var_dump shows type + value — incredibly useful for debugging
var_dump($isDiscounted); // Shows: bool(false)
var_dump($taxRate);      // Shows: float(0.08)

?>
Output
Product: Wireless Noise-Cancelling Headphones
Price: $97.19
In stock: Yes
Stock count: 142 units
First cart item: Headphones
Second cart item: USB Cable
Customer: James Okonkwo
Email: james@example.com
No discount code applied.
bool(false)
float(0.08)
Why PHP Calls Floats 'double':
When you run gettype() on a decimal number, PHP returns 'double' not 'float'. This is a historical quirk inherited from C — double refers to double-precision floating point. The two terms mean the same thing in PHP. Don't let it confuse you; is_float() and is_double() are also identical functions.
Production Insight
Array access by index starts at 0 — forgetting this causes 'Undefined index' notices.
In production, validate array keys with isset() before reading them.
Rule: never trust user input to be a valid array key without explicit existence check.
Key Takeaway
PHP has 8 data types across scalar, compound, and special families.
Arrays are the workhorse — indexed and associative cover 90% of use cases.
NULL means 'no value' — use it intentionally, not as a default.

Type Juggling and Type Casting — When PHP Changes Types Behind Your Back

PHP's loosely typed nature means it will sometimes change the type of a value automatically to make an operation work. This is called type juggling or type coercion. For example, if you try to add a number to a string that starts with a number, PHP quietly converts the string to an integer and adds them. This is either magic or madness depending on the situation.

Type casting is when YOU deliberately convert one type to another, using cast operators like (int), (float), (string), or (bool). This puts you in control rather than leaving it to PHP's automatic rules, which are notoriously surprising.

The comparison operator == (double equals) performs type juggling before comparing, which causes famous PHP gotchas like 0 == 'hello' evaluating to true in older PHP versions. The strict comparison operator === (triple equals) checks both value AND type without any conversion. Senior PHP developers use === by default and only reach for == when they specifically want type-flexible comparison. As a beginner, train yourself to use === from day one — it'll save you hours of debugging.

type_juggling_and_casting.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php

// ── TYPE JUGGLING (PHP does this automatically) ────────────────

$quantityAsString = "5";     // This is a STRING — it has quotes
$bonusQuantity = 3;          // This is an INTEGER

// PHP sees you're adding and converts $quantityAsString to int automatically
$totalQuantity = $quantityAsString + $bonusQuantity;
echo "Total quantity: $totalQuantity\n";        // Outputs: 8
echo "Type: " . gettype($totalQuantity) . "\n"; // Outputs: integer (PHP juggled the type)

// A string that DOESN'T start with a number becomes 0 in arithmetic
$nonsenseString = "apples";
$result = $nonsenseString + 10;
echo "Nonsense arithmetic result: $result\n"; // Outputs: 10 ("apples" became 0)

// ── TYPE CASTING (YOU control the conversion) ─────────────────

$rawInput = "42.7 degrees"; // Imagine this came from a form submission

$asInteger = (int) $rawInput;   // Casts to int — stops at the decimal point
$asFloat   = (float) $rawInput; // Casts to float — grabs 42.7, ignores " degrees"

echo "\nRaw input: $rawInput\n";
echo "Cast to int: $asInteger\n";   // Outputs: 42
echo "Cast to float: $asFloat\n";   // Outputs: 42.7

// Casting to boolean — useful to know what PHP considers 'falsy'
$emptyString   = (bool) "";    // false — empty string is falsy
$zeroValue     = (bool) 0;     // false — zero is falsy
$zeroString    = (bool) "0";   // false — the string "0" is ALSO falsy (a classic gotcha!)
$nonEmptyStr   = (bool) "hello"; // true  — any non-empty, non-"0" string is truthy

echo "\n--- Boolean casts ---\n";
var_dump($emptyString);  // bool(false)
var_dump($zeroValue);    // bool(false)
var_dump($zeroString);   // bool(false) ← catches people out!
var_dump($nonEmptyStr);  // bool(true)

// ── LOOSE vs STRICT COMPARISON ────────────────────────────────

$formInput = "10"; // String from a form field
$dbValue   = 10;   // Integer from a database

// == (loose): converts types before comparing — both become 10, so true
$looseResult = ($formInput == $dbValue);
echo "\nLoose comparison (==): " . ($looseResult ? "true" : "false") . "\n"; // true

// === (strict): checks type AND value — string vs integer, so false
$strictResult = ($formInput === $dbValue);
echo "Strict comparison (===): " . ($strictResult ? "true" : "false") . "\n"; // false

?>
Output
Total quantity: 8
Type: integer
Nonsense arithmetic result: 10
Raw input: 42.7 degrees
Cast to int: 42
Cast to float: 42.7
--- Boolean casts ---
bool(false)
bool(false)
bool(false)
bool(true)
Loose comparison (==): true
Strict comparison (===): false
Watch Out:
The string "0" casts to boolean false — but the string "false" casts to boolean TRUE. PHP checks if a string is empty or literally "0", not whether it spells out the word false. This trips up even experienced developers. Always use strict comparisons (===) when checking user input against expected values.
Production Insight
A loose comparison between user input and a numeric database value can silently bypass authentication.
The fix is simple: use === everywhere, especially for security checks.
Rule: if you ever write == in production, ask yourself 'why am I not using ===?'
Key Takeaway
Type juggling is automatic — never assume your value's type stays the same.
Explicit casting with (int), (float), (string), (bool) gives you control.
Strict comparison (===) is the default choice for production code.

Variable Scope — Where Your Variables Live and Die

In PHP, not all variables are visible everywhere. The scope of a variable determines where it can be accessed. The main scopes are: local (inside a function), global (outside any function), static (persistent across function calls), and superglobal (available everywhere — like $_POST, $_SESSION).

Variables defined inside a function are local to that function — they don't exist outside it. If you need to use a global variable inside a function, you must explicitly import it with the 'global' keyword. This is different from many other languages and catches beginners off guard. PHP's function scope is intentionally isolated to prevent accidental side effects, but it also means you must think carefully about which variables need to cross boundaries.

Static variables inside functions retain their value between calls — perfect for counters or caches. Superglobals like $_GET, $_POST, $_SERVER are built-in arrays that hold request data and are accessible everywhere without any special declaration.

variable_scope.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php

// Global variable
$globalCounter = 10;

function increment() {
    // This is a local variable — it only exists inside this function
    $localCounter = 0;
    $localCounter++;
    echo "Local counter: $localCounter\n"; // Each call: 1
    
    // To use the global $globalCounter, we need the 'global' keyword
    global $globalCounter;
    $globalCounter++;
    echo "Global counter inside function: $globalCounter\n";
}

increment(); // Local: 1, Global: 11
increment(); // Local: 1, Global: 12
increment(); // Local: 1, Global: 13

// Static variable example
function counterWithStatic() {
    static $staticCount = 0; // Initialized only once, persists across calls
    $staticCount++;
    echo "Static count: $staticCount\n";
}

counterWithStatic(); // 1
counterWithStatic(); // 2
counterWithStatic(); // 3

// Superglobal $_GET example (simulated with a query string)
// Assume URL: index.php?name=Maria
if (isset($_GET['name'])) {
    $visitor = $_GET['name'];
    echo "Hello, $visitor!\n";
}

?>

<!-- Note: Superglobals are always available -->
Output
Local counter: 1
Global counter inside function: 11
Local counter: 1
Global counter inside function: 12
Local counter: 1
Global counter inside function: 13
Static count: 1
Static count: 2
Static count: 3
Hello, Maria!
Scope Tip:
Avoid using 'global' inside functions if you can. Instead, pass values as parameters and return results. This makes your functions predictable and testable. Global variables are a code smell — they couple your function to the outside world and make refactoring painful.
Production Insight
In production, relying on global variables inside functions makes debugging a nightmare — you never know which function changed the value.
Use function parameters and return values instead; they make data flow explicit.
Rule: globals are for application-wide configuration constants, not mutable state.
Key Takeaway
Local variables vanish when the function ends — use parameters and returns.
Static variables persist between calls — good for counters and caches.
Superglobals like $_GET, $_POST are always available anywhere — but treat them as read-only inputs.

Constants and define() — Values That Never Change

Sometimes you need a value that should never be reassigned — like the tax rate for your store or the API version number. PHP gives you two ways to define constants: the define() function (old style) and the const keyword (new style, available since PHP 5.3). Constants are automatically global — you can use them anywhere in your script without the 'global' keyword.

The main difference: define() can be called inside control structures (like loops or if blocks), while const must be used at the top level of a file. const also works inside classes to define class constants. Both follow the naming convention of all-uppercase with underscores (TAX_RATE, MAX_LOGIN_ATTEMPTS), but this is a convention — not enforced by PHP.

Magic constants like __FILE__, __LINE__, __DIR__ are predefined constants that change based on where they're used. They're incredibly useful for debugging and logging because they tell you exactly where your code is executing.

constants.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php

// Define a constant using define() — old style but still widely used
define('TAX_RATE', 0.08);
define('APP_NAME', 'MyStore');

// Define a constant using const — only allowed at top level
const MAX_LOGIN_ATTEMPTS = 5;

// Using constants — note: no dollar sign!
echo "Welcome to " . APP_NAME . "\n";
echo "Tax rate: " . (TAX_RATE * 100) . "%\n";
echo "Max login attempts: " . MAX_LOGIN_ATTEMPTS . "\n";

// Magic constants — change depending on context
echo "This file: " . __FILE__ . "\n";
echo "This line: " . __LINE__ . "\n";
echo "This function: " . __FUNCTION__ . "\n"; // empty because not inside a function

function test() {
    echo "Inside function: " . __FUNCTION__ . "\n";
}
test();

// Constants are case-insensitive by default, but stick to uppercase for clarity
// echo Tax_Rate; // Works but don't do this — confusing

// Trying to reassign a constant causes an error
// define('TAX_RATE', 0.10); // Warning: Constant TAX_RATE already defined

?>

<!-- Output:
Welcome to MyStore
Tax rate: 8%
Max login attempts: 5
This file: /var/www/constants.php
This line: 15
This function:
Inside function: test
-->
Output
Welcome to MyStore
Tax rate: 8%
Max login attempts: 5
This file: /var/www/constants.php
This line: 15
This function:
Inside function: test
When to Use Constants:
Use constants for configuration values that never change during a request — database host, API keys, file paths, tax rates. Magic constants are perfect for logging: include __FILE__ and __LINE__ in your error messages to pinpoint exactly where something went wrong.
Production Insight
In production, using constants instead of magic strings prevents typos and makes refactoring easier.
If you change a database table name, update the constant once, not every WHERE clause.
Rule: any value that's the same across the entire codebase should be a constant, not a variable.
Key Takeaway
define() or const — choose const for modern code at top level, define() for conditional constants.
Constants are global and never reassignable — perfect for configuration.
Magic constants (__FILE__, __LINE__) are your logging allies.

Strict Typing and Type Declarations — Taming PHP's Loose Nature

PHP 7 introduced optional type declarations for function parameters and return values. PHP 8 expanded them further. With declare(strict_types=1) at the top of a file, PHP enforces that a function receives exactly the declared type — no automatic conversion. Without it, PHP will still try to juggle types even if you declare them.

Strict mode is a game-changer for production code. It turns type-related bugs from silent logic errors into immediate fatal errors. You don't want to find out at 3 AM that a function meant to receive an integer got a string and quietly returned wrong results. Strict mode forces you to be explicit about the types flowing through your system.

For beginners, it's okay to start without strict types, but once you're comfortable, turn them on in every file. They make your code self-documenting and catch a whole class of bugs before they reach users.

strict_types.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

declare(strict_types=1); // THIS LINE MUST BE THE FIRST LINE AFTER <?php

// Enforced type declarations
function calculateTotal(float $price, int $quantity): float {
    return $price * $quantity;
}

// Works fine — both arguments are correct types
$total = calculateTotal(29.99, 3);
echo "Total: $" . number_format($total, 2) . "\n"; // 89.97

// Without strict_types, PHP would convert '3' to int 3 and work silently
// With strict_types, this will throw a TypeError:
// $total = calculateTotal(29.99, '3'); // TypeError: Argument 2 must be of type int, string given

// Strict return type — must match exactly
function getPrice(): float {
    return 19.99; // float is fine
}

// The following would fail:
// function getPrice(): float {
//     return '19.99'; // TypeError: Return value must be of type float, string returned
// }

echo "Price: $" . getPrice() . "\n";

?>

<!-- Output:
Total: $89.97
Price: $19.99
-->
Output
Total: $89.97
Price: $19.99
Strict Types Caveat:
declare(strict_types=1) only affects the file it's in — it does NOT affect other files that call functions from this file. If you call a strict-typed function from a non-strict file, PHP will still juggle types before the call, potentially causing a TypeError. For full coverage, add strict_types=1 to every PHP file.
Production Insight
Adding strict_types=1 to even a single file can prevent a chain of silent data corruption.
A team I worked with had a bug where a float was being passed as a string in an API call — strict mode caught it instantly.
Rule: add declare(strict_types=1) to every production PHP file — no exceptions.
Key Takeaway
declare(strict_types=1) forces type safety — catch mismatches early.
Type declarations on parameters and returns make your code contract explicit.
Strict mode catches bugs that would otherwise silently corrupt data.
● Production incidentPOST-MORTEMseverity: high

The PayPal Type Juggling Bug Exposed

Symptom
Users could log in as any account by sending an empty password or numeric zero in the password field.
Assumption
The team assumed boolean false and empty string were different in all contexts.
Root cause
The code used if ($user->isAdmin == $input) where $user->isAdmin might be 0 (false) and $input was '0' (string). Loose comparison (==) treated 0 == '0' as true, so any user sending a password equal to '0' was authenticated.
Fix
Replace all sensitive comparisons with strict equality (===) or type-safe input validation. Never rely on loose comparison for authentication or authorization checks.
Key lesson
  • Never use == for security-critical comparisons — always ===.
  • PHP's type juggling makes 0 == '0' true, 0 == 'false' false, and 'false' == 0 true — these aren't intuitive.
  • Apply declare(strict_types=1) in all production files to prevent unintended type coercion.
Production debug guideSymptom → Action guide for type-related bugs4 entries
Symptom · 01
Variable holds unexpected value after arithmetic
Fix
Use var_dump() to inspect the type. If a string like '5 apples' appears as 5, PHP juggled it. Cast explicitly with (int) or use is_numeric() first.
Symptom · 02
Condition always true when checking password match
Fix
Check if you used == instead of ===. Replace with === and verify both operands have same type.
Symptom · 03
Array index gives 'Undefined array key' notice
Fix
Confirm the array index exists with isset() or array_key_exists(). Remember array keys start at 0.
Symptom · 04
Null value crashes string concatenation
Fix
Use ?? operator (null coalescing) or is_null() check before using the variable. Explicitly handle null cases.
★ PHP Type Debug Cheat SheetFive-second commands for the four most common type headaches
What type is this variable?
Immediate action
Insert var_dump($var);
Commands
var_dump($var);
gettype($var);
Fix now
Use gettype() for quick type string, var_dump() for full inspection.
String vs numeric comparison weirdness+
Immediate action
Change == to === and check types
Commands
var_dump($stringValue === $numericValue);
var_dump(is_numeric($stringValue));
Fix now
Cast one side explicitly: (int)$stringValue === $numericValue
Array key doesn't exist but should+
Immediate action
Check if the array is null or empty first
Commands
isset($array[$key]);
array_key_exists($key, $array);
Fix now
Use null coalescing: $value = $array[$key] ?? 'default';
Boolean value not what you expected+
Immediate action
Cast to bool with (bool) and inspect
Commands
var_dump((bool)$value);
var_dump($value);
Fix now
Remember: empty string, '0', 0, 0.0, null, false, [] are falsy; everything else is truthy.
PHP Data Types at a Glance
Data TypeExample ValueUse CaseFalsy WhenPHP Type Check Function
String"hello@example.com"Names, emails, messages, HTMLEmpty string "" or "0"is_string()
Integer42 or -7Counts, IDs, ages, quantitiesValue is 0is_int()
Float19.99 or 0.075Prices, percentages, coordinatesValue is 0.0is_float()
Booleantrue or falseFlags, toggles, conditionsValue is falseis_bool()
Array["a", "b"] or ["key"=>"val"]Lists, records, config settingsEmpty array []is_array()
NULLnullMissing data, unset variablesAlways falsyis_null()

Key takeaways

1
Every PHP variable starts with $
this is non-negotiable syntax, not a style choice, and omitting it causes an immediate parse error.
2
PHP has four scalar types (string, int, float, bool), two compound types (array, object), and two special types (null, resource)
knowing which to reach for is a core skill.
3
Always use === (triple equals) for comparisons by default
== silently converts types before comparing and produces counterintuitive results that are hard to debug.
4
The string "0" is falsy in PHP but the string "false" is truthy
PHP's truthiness rules follow strict internal logic, not human intuition, so test edge cases with var_dump().
5
Variable scope in PHP is local to functions by default
use the 'global' keyword or pass parameters to access variables from outside, but prefer parameters for cleaner code.
6
Constants (define() or const) hold values that never change
use them for configuration and magic constants (__FILE__, __LINE__) for debugging logs.
7
declare(strict_types=1) enforces type safety on function parameters and return values
add it to every production PHP file to catch type bugs early.

Common mistakes to avoid

5 patterns
×

Using = instead of == or === in conditions

Symptom
Writing if ($userAge = 18) instead of if ($userAge === 18) assigns 18 to $userAge and the condition always evaluates as true because 18 is truthy. PHP won't throw an error, making this silent and deadly.
Fix
Always use === for comparisons inside if statements. Consider enabling strict mode with declare(strict_types=1) at the top of your files to catch such mistakes at compile time.
×

Forgetting that array indexes start at 0, not 1

Symptom
If you create $colours = ["red", "green", "blue"] and try to access $colours[3], you'll get an 'Undefined array key 3' notice and an empty value, because the last item is at index 2.
Fix
Remember the rule: the last valid index is always (count of items - 1). Use count($colours) - 1 to get the last index dynamically, or use PHP's end() function to grab the last element safely.
×

Using single quotes when you expect variable interpolation to work

Symptom
Writing echo 'Hello, $customerName!' will literally print the dollar sign and variable name as text, not the value stored inside it. Single quotes in PHP are completely literal — no variables are evaluated inside them.
Fix
Switch to double quotes when you want PHP to replace variables with their values: echo "Hello, $customerName!" — or use concatenation: echo 'Hello, ' . $customerName . '!'.
×

Assuming loose comparison (==) behaves like strict (===)

Symptom
Comparing 0 == 'hello' returns true in older PHP versions, and 0 == '0' is always true. This can cause unexpected authentication bypasses or data corruption when comparing user input against stored values.
Fix
Always use === unless you have a very specific reason to allow type juggling. For security-sensitive checks, never use ==.
×

Not validating array keys before accessing them

Symptom
Accessing $_POST['username'] without checking if the key exists can trigger an 'Undefined index' notice, or worse, null values propagating through your application silently.
Fix
Use isset() or array_key_exists() before reading a key. Use the null coalescing operator (?? ) to provide a default: $username = $_POST['username'] ?? '';
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the difference between == and === in PHP, and when would using =...
Q02SENIOR
PHP is described as loosely typed — what does that mean exactly, and wha...
Q03SENIOR
If a variable is declared as $count = '0', what does var_dump((bool) $co...
Q04SENIOR
Explain the difference between define() and const for declaring constant...
Q01 of 04JUNIOR

What is the difference between == and === in PHP, and when would using == instead of === cause a bug in production code?

ANSWER
== is a loose comparison operator that performs type juggling before comparing values. === is a strict comparison that checks both value and type without any conversion. In production, using == can cause authentication bypass bugs (e.g., 0 == '0' is true) and data corruption in financial calculations. Always use === as the default, and only use == when you have a specific need for type flexibility, such as comparing numbers that may come as strings from a form.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Do I need to declare a variable type in PHP before using it?
02
What is the difference between null and an empty string in PHP?
03
Why does PHP use a dollar sign ($) for variables?
04
Can I change a constant's value after defining it?
05
What's the difference between single and double quotes in PHP?
🔥

That's PHP Basics. Mark it forged?

6 min read · try the examples if you haven't

Previous
Introduction to PHP
2 / 14 · PHP Basics
Next
PHP Operators