Przejdź do głównej zawartości

Dobre praktyki pisania kodu PHP

Dobre praktyki programistyczne to sprawdzone zasady, które pomagaja pisac kod łatwiejszy do zrozumienia, utrzymania i rozwijania. W PHP szczegolnie ważne jest przestrzeganie tych zasad, ponieważ język pozwala na wiele “skrotow”, które prowadza do trudnego w utrzymaniu kodu.

Czysty kod to nie tylko estetyka - to oszczednosc czasu, mniej błędów i lepsza współpraca w zespole.

Kod, który jest łatwy do zrozumienia i modyfikacji. Każda funkcja robi jedna rzecz, nazwy sa opisowe, a struktura jest przejrzysta.

Nie powtarzaj kodu - jeśli cos piszesz dwa razy, zrob z tego funkcje.

Proste rozwiązania sa lepsze od skomplikowanych.

Piec zasad projektowania obiektowego (dla zaawansowanych).

<?php
// ZLE - nieczytelne nazwy
$x = "Jan Kowalski";
$a = 25;
$arr = [];
// DOBRZE - opisowe nazwy
$userName = "Jan Kowalski";
$userAge = 25;
$orderItems = [];
// ZLE - skroty
$usrNm = "Jan";
$prc = 99.99;
// DOBRZE - pełne słowa
$userName = "Jan";
$price = 99.99;
ElementKonwencjaPrzykład
ZmiennecamelCase$userName, $orderTotal
FunkcjecamelCasegetUserById(), calculateTotal()
KlasyPascalCaseUserController, OrderService
StałeUPPER_SNAKEMAX_LOGIN_ATTEMPTS, DB_HOST
<?php
// ZLE - brak wciec, nieczytelne
function processOrder($order){
if($order->status=='pending'){
$total=$order->calculateTotal();
if($total>100){$order->applyDiscount(10);}
$order->save();
return true;}
return false;}
// DOBRZE - czytelne formatowanie
function processOrder(Order $order): bool
{
if ($order->status !== 'pending') {
return false;
}
$total = $order->calculateTotal();
if ($total > 100) {
$order->applyDiscount(10);
}
$order->save();
return true;
}
<?php
// ZLE - powtorzony kod
function getActiveUsers($pdo) {
$stmt = $pdo->prepare("SELECT * FROM users WHERE status = 'active'");
$stmt->execute();
return $stmt->fetchAll();
}
function getInactiveUsers($pdo) {
$stmt = $pdo->prepare("SELECT * FROM users WHERE status = 'inactive'");
$stmt->execute();
return $stmt->fetchAll();
}
function getPendingUsers($pdo) {
$stmt = $pdo->prepare("SELECT * FROM users WHERE status = 'pending'");
$stmt->execute();
return $stmt->fetchAll();
}
// DOBRZE - jedna funkcja z parametrem
function getUsersByStatus(PDO $pdo, string $status): array
{
$stmt = $pdo->prepare("SELECT * FROM users WHERE status = ?");
$stmt->execute([$status]);
return $stmt->fetchAll();
}
// Użycie
$activeUsers = getUsersByStatus($pdo, 'active');
$inactiveUsers = getUsersByStatus($pdo, 'inactive');
<?php
// ZLE - funkcja robi za dużo
function processUserRegistration($data) {
// Walidacja
if (empty($data['email'])) {
return ['error' => 'Email required'];
}
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
return ['error' => 'Invalid email'];
}
if (strlen($data['password']) < 8) {
return ['error' => 'Password too short'];
}
// Zapis do bazy
$hash = password_hash($data['password'], PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users ...");
$stmt->execute([...]);
// Wysłanie e-maila
mail($data['email'], 'Welcome!', '...');
return ['success' => true];
}
// DOBRZE - podział na mniejsze funkcje
function validateUserData(array $data): ?string
{
if (empty($data['email'])) {
return 'Email wymagany';
}
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
return 'Nieprawidłowy email';
}
if (strlen($data['password']) < 8) {
return 'Hasło za krótkie';
}
return null; // Brak błędów
}
function createUser(PDO $pdo, array $data): int
{
$hash = password_hash($data['password'], PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (email, password) VALUES (?, ?)");
$stmt->execute([$data['email'], $hash]);
return $pdo->lastInsertId();
}
function sendWelcomeEmail(string $email): void
{
mail($email, 'Witamy!', 'Dziekujemy za rejestracje.');
}
// Użycie - czytelny przepływ
$error = validateUserData($data);
if ($error) {
return ['error' => $error];
}
$userId = createUser($pdo, $data);
sendWelcomeEmail($data['email']);
<?php
// ZLE - podatne na SQL Injection
$username = $_POST['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
$result = $pdo->query($query);
// DOBRZE - prepared statement
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$_POST['username']]);
$user = $stmt->fetch();
<?php
// ZLE - podatne na XSS
echo "Witaj, " . $_GET['name'];
// DOBRZE - escapowanie
echo "Witaj, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
<?php
// DOBRZE - walidacja przed użyciem
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT);
if (!$email) {
die('Nieprawidłowy email');
}
if ($age === false || $age < 0 || $age > 150) {
die('Nieprawidłowy wiek');
}
<?php
// ZLE - ukrywanie błędów
$result = @file_get_contents('plik.txt');
// ZLE - generyczne komunikaty
try {
// kod
} catch (Exception $e) {
echo "Błąd";
}
// DOBRZE - właściwa obsługa
try {
$content = file_get_contents('plik.txt');
if ($content === false) {
throw new RuntimeException('Nie można odczytać pliku');
}
} catch (RuntimeException $e) {
error_log($e->getMessage()); // Loguj błąd
echo "Przepraszamy, wystąpił problem."; // User-friendly komunikat
}
<?php
// ZLE - brak typow
function calculateDiscount($price, $percentage) {
return $price * ($percentage / 100);
}
// DOBRZE - typy i dokumentacja
/**
* Oblicza rabat od ceny
*
* @param float $price Cena produktu
* @param float $percentage Procent rabatu (0-100)
* @return float Wartość rabatu
*/
function calculateDiscount(float $price, float $percentage): float
{
if ($percentage < 0 || $percentage > 100) {
throw new InvalidArgumentException('Percentage must be 0-100');
}
return $price * ($percentage / 100);
}
<?php
// Nieczytelny, powtarzajacy się, niebezpieczny kod
$u = $_POST['u'];
$p = $_POST['p'];
$q = "SELECT * FROM users WHERE username='$u'";
$r = mysqli_query($conn, $q);
$row = mysqli_fetch_assoc($r);
if($row['password'] == $p) {
$_SESSION['logged'] = true;
$_SESSION['user'] = $row['username'];
header('Location: dashboard.php');
} else {
echo "Źle dane";
}
<?php
declare(strict_types=1);
function authenticateUser(PDO $pdo, string $username, string $password): ?array
{
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user || !password_verify($password, $user['password_hash'])) {
return null;
}
return $user;
}
function loginUser(array $user): void
{
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
}
// Użycie
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
$user = authenticateUser($pdo, $username, $password);
if ($user) {
loginUser($user);
header('Location: dashboard.php');
exit;
}
$error = 'Nieprawidłowy login lub hasło';
  • Uzywaj opisowych nazw zmiennych i funkcji
  • Przestrzegaj zasady DRY - nie powtarzaj kodu
  • Jedna funkcja = jedno zadanie
  • Zawsze uzywaj prepared statements (SQL)
  • Escapuj dane wyjsciowe (XSS)
  • Dodawaj type hints i return types
  • Obsługuj błędy właściwie
  • Formatuj kod konsekwentnie