PHP Common Mistakes & Best Practices
In this page:
Loose vs Strict Equality
== silently converts operand types before comparing, which produces surprising results like 0 == abc evaluating to true in older PHP versions; === compares both value and type, avoiding that entire class of bug.
Example: Loose vs Strict Equality
<?php
// Print a detailed dump (with types) of `"0" == "abc"`
var_dump("0" == "abc");
// Print a detailed dump (with types) of `"0" === "abc"`
var_dump("0" === "abc");
?>
Login to try C/C++/Java/PHP code in the editor
Uninitialized Array Keys
Reading an array key that was never set triggers a warning (or an error in strict contexts); checking isset() or array_key_exists() first avoids both the warning and any downstream logic relying on an undefined value.
Example: Uninitialized Array Keys
<?php
// Declare `$user` as an array: `["name" => "Alice"]`
$user = ["name" => "Alice"];
// Check whether `isset($user['email'])`
if (isset($user['email'])) {
// Print `$user['email']` to the output
echo $user['email'];
// Otherwise, run this branch
} else {
// Print "Email key not set" to the output
echo "Email key not set";
}
?>
Login to try C/C++/Java/PHP code in the editor
SQL Injection Vulnerabilities
Directly concatenating user input into a SQL string opens the door to injection attacks that can read or destroy your entire database; prepared statements eliminate the risk by keeping data separate from query structure.
Example: SQL Injection Vulnerabilities
<?php
// Create a new `PDO` instance with 'sqlite::memory:', stored in `$pdo`
$pdo = new PDO('sqlite::memory:');
$pdo->exec("CREATE TABLE users (id INTEGER, name TEXT)");
$name = "Robert'); DROP TABLE users;";
// Declare `$stmt`, set to `$pdo->prepare("INSERT INTO users (name) VALUES (?)")`
$stmt = $pdo->prepare("INSERT INTO users (name) VALUES (?)");
$stmt->execute([$name]);
// Print "Safe -- prepared statement kept structure and data separate" to the output
echo "Safe -- prepared statement kept structure and data separate";
?>
Login to try C/C++/Java/PHP code in the editor
Variable Scope Leaks
Overusing global variables makes it hard to know what a function actually depends on or might change, since its behavior isn't fully described by its parameters -- keeping state local and passed explicitly avoids that hidden coupling.
Example: Variable Scope Leaks
<?php
$counter = 0;
function increment() {
global $counter;
$counter++;
}
increment();
echo $counter;
// Depending on a global hides this function's real dependency
?>
Login to try C/C++/Java/PHP code in the editor
Best Practices Checklist
A solid production checklist -- validate every input, handle errors consistently, and turn off error display -- catches the majority of security and reliability issues before they ever reach real users.
Example: Best Practices Checklist
<?php
// Declare `$email`, set to `$_POST['email'] ?? ''`
$email = $_POST['email'] ?? '';
// Check whether `!filter_var($email, FILTER_VALIDATE_EMAIL)`
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
// Print "Invalid email" to the output
echo "Invalid email";
}
// Call `ini_set('display_errors', '0')`
ini_set('display_errors', '0');
?>
Login to try C/C++/Java/PHP code in the editor
- Using
==when===is needed, so"0" == falseand similar loose comparisons cause bugs. - Reading an array key without checking
issetor using??, which raises a warning. - Building SQL by concatenating user input instead of using prepared statements.
- Tools such as PHPUnit, Xdebug, and PSR standards help test, debug, and style code.
- Git integration, deployment and hosting, and the command line support development workflows.
- WebSockets, email sending, and image processing extend what PHP can do, and best practices help avoid common mistakes.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: