PHP Best Practices
This page is a wrap-up checklist for everything covered in this PHP tutorial: security, code organization, error handling, performance, database access, sessions/cookies, and a few general habits worth carrying into every project you build.
1) Security Recap
Never trust input, and never trust what goes back out either. See PHP Security and Form Validation for the full walkthrough.
<?php
// Escape output to prevent XSS
echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
// Hash passwords - never store plain text
$hash = password_hash($password, PASSWORD_DEFAULT);
?>
- Always escape output with
htmlspecialchars()before printing user data. - Always use prepared statements for SQL — never concatenate raw input into a query.
- Hash passwords with
password_hash(); verify withpassword_verify(). - Validate everything server-side, even if it was already validated in JavaScript.
2) Code Organization
Keep logic and presentation apart so pages stay readable as they grow. See Includes.
<?php
// header.php, footer.php, sidebar.php kept separate and reused
include_once('php-header.php');
// Business logic in a function, not mixed into the markup
function calculateDiscount(float $price, float $percent): float {
return $price - ($price * $percent / 100);
}
?>
- Separate logic (functions, classes) from presentation (HTML output).
- Reuse header/sidebar/footer with
include_onceinstead of copy-pasting markup. - Use meaningful, descriptive names for variables and functions.
3) Error Handling
Never show raw errors to visitors in production. Full details on PHP Error Handling.
<?php
// Production settings
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php/app-errors.log');
?>
- Turn
display_errorsoff andlog_errorson in production. - Wrap risky operations in
try/catchand use custom exception classes where useful. - Log enough detail (message, file, line) to debug later without exposing it to users.
4) Performance
Small habits keep pages fast as data grows.
<?php
// Bad: one query per loop iteration (N+1 problem)
foreach ($userIds as $id) {
$stmt = $pdo->query("SELECT * FROM users WHERE id={$id}");
}
// Good: fetch everything needed in one query, outside the loop
$stmt = $pdo->prepare('SELECT * FROM users WHERE id IN (?)');
?>
- Avoid running database queries inside loops — fetch what you need in one query.
- Cache results that don't change often (config, lookups) instead of recomputing them.
- Close database connections/free result sets when a script no longer needs them.
5) Database Access
See PHP & MySQL for the full connection and query walkthrough.
<?php
$stmt = $pdo->prepare('SELECT id, title FROM posts ORDER BY id DESC LIMIT ?');
$stmt->execute([20]);
$posts = $stmt->fetchAll();
?>
- Always use prepared statements — never build SQL with string concatenation.
- Use
LIMITwhen reading from large tables instead of loading everything. - Index columns you filter or sort on frequently.
6) Sessions & Cookies
See Sessions and Cookies for details.
<?php
session_start();
// After a successful login, always regenerate the session ID
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
// Cookies: reasonable expiry, not "never expires"
setcookie('remember_me', '1', time() + 86400 * 7);
?>
- Call
session_regenerate_id()right after login to prevent session fixation. - Set a reasonable cookie expiry — avoid cookies that never expire.
- Mark sensitive cookies
HttpOnlyandSecurewhere possible.
7) General Habits
A few habits that pay off across every project.
<?php
// This site's own php-forms.php starts with exactly this line
declare(strict_types=1);
?>
- Keep your PHP version updated to receive security and performance fixes.
- Use
declare(strict_types=1)so type hints are enforced strictly — this tutorial's own php-forms.php page opens with this exact line. - Read the changelog before upgrading — see What's New in PHP 8.
| Area | One-line rule |
|---|---|
| Security | Escape output, prepare queries, hash passwords, validate server-side. |
| Organization | Split logic from markup; reuse includes and functions. |
| Error handling | Log in production, never display raw errors to users. |
| Performance | No queries inside loops; cache and close what you don't need open. |
| Database | Prepared statements always; LIMIT on large tables. |
| Sessions/cookies | Regenerate session ID after login; set sane cookie expiry. |
| General | Stay updated; use strict_types for safer code. |