Core Concept
DRY emphasizes that every piece of knowledge in a system should have a single, unambiguous representation.
Examples of Code Violating DRY
Example 1: Validation Logic
// WET (Write Everything Twice) Code
class User {
public function validateUsername($username) {
if (strlen($username) < 3 || strlen($username) > 20) {
throw new Exception("Username must be between 3 and 20 characters");
}
if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
throw new Exception("Username can only contain letters, numbers and underscore");
}
}
public function updateUsername($username) {
// Same validation repeated
if (strlen($username) < 3 || strlen($username) > 20) {
throw new Exception("Username must be between 3 and 20 characters");
}
if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
throw new Exception("Username can only contain letters, numbers and underscore");
}
// Update logic
}
}
DRY Solution
class User {
private function validateUsername($username) {
if (strlen($username) < 3 || strlen($username) > 20) {
throw new Exception("Username must be between 3 and 20 characters");
}
if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
throw new Exception("Username can only contain letters, numbers and underscore");
}
}
public function createUser($username) {
$this->validateUsername($username);
// Creation logic
}
public function updateUsername($username) {
$this->validateUsername($username);
// Update logic
}
}
Implementing DRY with Inheritance
abstract class BaseController {
protected function jsonResponse($data, $status = 200) {
header('Content-Type: application/json');
http_response_code($status);
echo json_encode($data);
}
}
class UserController extends BaseController {
public function show($id) {
$user = User::find($id);
return $this->jsonResponse($user);
}
}
class ProductController extends BaseController {
public function show($id) {
$product = Product::find($id);
return $this->jsonResponse($product);
}
}
Using Traits for DRY
trait Loggable {
private function log($message) {
$timestamp = date('Y-m-d H:i:s');
file_put_contents('log.txt', "[$timestamp] $message\n", FILE_APPEND);
}
}
class UserService {
use Loggable;
public function createUser($data) {
$this->log("Creating new user");
// User creation logic
}
}
class PaymentService {
use Loggable;
public function processPayment($amount) {
$this->log("Processing payment: $amount");
// Payment processing logic
}
}
Using Constants
class Config {
const DEFAULT_ITEMS_PER_PAGE = 10;
const MAX_UPLOAD_SIZE = 5242880; // 5MB
const ALLOWED_FILE_TYPES = ['jpg', 'png', 'pdf'];
}
class FileUploadService {
public function validateFile($file) {
if ($file['size'] > Config::MAX_UPLOAD_SIZE) {
throw new Exception("File too large");
}
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
if (!in_array($extension, Config::ALLOWED_FILE_TYPES)) {
throw new Exception("Invalid file type");
}
}
}
class MediaController {
public function index() {
return $this->paginate(Config::DEFAULT_ITEMS_PER_PAGE);
}
}
These examples demonstrate how to apply DRY through various PHP features like inheritance, traits, constants, and proper method extraction. The goal is to maintain a single source of truth for any given functionality in your codebase.
Top comments (0)