Design patterns are reusable solutions to common software design problems. They provide a structured approach to designing code that is flexible, maintainable, and scalable. Here are a few commonly used design patterns in PHP with examples:
- Factory Pattern:
The Factory pattern provides an interface for creating objects without specifying their concrete classes. It allows you to centralize the object creation logic. Here’s an example:
interface Logger {
public function log($message);
}
class FileLogger implements Logger {
public function log($message) {
echo "Logging message to a file: $message";
}
}
class DatabaseLogger implements Logger {
public function log($message) {
echo "Logging message to a database: $message";
}
}
class LoggerFactory {
public static function createLogger($type) {
if ($type === 'file') {
return new FileLogger();
} elseif ($type === 'database') {
return new DatabaseLogger();
}
return null;
}
}
// Usage:
$logger = LoggerFactory::createLogger('file');
$logger->log("Error occurred."); // Output: Logging message to a file: Error occurred.
- Observer Pattern:
The Observer pattern establishes a one-to-many dependency between objects. When the state of one object changes, all its dependent objects (observers) are automatically notified and updated. Here’s an example:
interface Observer {
public function update($data);
}
class Subject {
private $observers = [];
public function attach(Observer $observer) {
$this->observers[] = $observer;
}
public function detach(Observer $observer) {
$index = array_search($observer, $this->observers);
if ($index !== false) {
unset($this->observers[$index]);
}
}
public function notify($data) {
foreach ($this->observers as $observer) {
$observer->update($data);
}
}
public function doSomething() {
// Perform some action
// Notify observers
$this->notify('Some data');
}
}
class ConcreteObserver implements Observer {
public function update($data) {
echo "Received data: $data";
}
}
// Usage:
$subject = new Subject();
$observer1 = new ConcreteObserver();
$observer2 = new ConcreteObserver();
$subject->attach($observer1);
$subject->attach($observer2);
$subject->doSomething(); // Output: Received data: Some data
- Repository Pattern:
The Repository pattern separates the data access logic from the business logic. It provides a way to encapsulate data operations and abstracts the underlying data storage implementation. Here’s an example:
class UserRepository {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
public function findById($id) {
// Database query to retrieve user by ID
return $this->db->query("SELECT * FROM users WHERE id = $id");
}
public function save($user) {
// Database query to save user data
$this->db->query("INSERT INTO users (name, email) VALUES ('$user->name', '$user->email')");
}
}
// Usage:
$db = new Database(); // Assume Database class exists
$userRepository = new UserRepository($db);
$user = $userRepository->findById(1);
echo "User ID: " . $user['id']; // Output: User ID: 1
$newUser = new User("John Doe", "john@example.com");
$userRepository->save($newUser);
These are just a few examples of design patterns in PHP. Design patterns help in creating modular, reusable, and maintainable code by following established best practices and principles.