PHP - Namespace, Autoloader, Message-Handler und ORM
Datum: November 2021
Lesedauer: 3 Minuten
Mein letzter Blogpost handelte von den PHP-Grundlagen. Nun schreibe ich vertiefter über vier weitere Themen:
- Namespace
- Autoloader
- Message-Handler
- Object Relational Mapper (ORM)
Namespace
Namensräume bieten zwei bedeutungsvolle Vorteile:
- Elemente (Klassen, Funktionen und Konstanten) können denselben Namen haben.
- Code kann in logische Gruppen unterteilt werden.
Dabei treten mithilfe der namespaces keine collisions auf.
Verwendung
Um von den Vorteilen der namespaces Gebrauch zu machen, muss man das namespace-Keyword verwenden.
<?php
namespace Data;
class Database {
public function __construct() {
echo "Fully qualified class name: ".__CLASS__."\n";
}
}
?>Nachdem man die Klasse mit use eingebunden hat, kann man sie verwenden.
<?php
use Data\Database;
require "Database.php";
$db = new Database();
?>Autoloader
Im obigen Beispiel kann man erkennen, dass die Klassen, welche man verwenden will, inkludiert werden müssen. Das manuelle Einbinden hat jedoch zwei
Probleme:
- Aufwand – Hat man viele Klassen, kostet das Einbinden viel Zeit.
- Fehleranfälligkeit – Verschiebt man eine Klasse, muss man den Pfad anpassen.
Ein autoloader löst diese Probleme, indem er die entsprechenden Dateien sucht und korrekt einbindet.
function autoload($className) {
$className = ltrim('classes/' . $className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
}
spl_autoload_register('autoload');Hier wird auf Zeile 2 definiert, dass sich die Klassen im Ordner classes befinden.
Message-Handler
Bei meiner Webanwendung kann der User Daten bearbeiten. Beim Speichern soll er Feedback erhalten.
Mein initialer Ansatz hatte jedoch zwei Probleme:
- Es konnten keine Nachrichten gesammelt werden.
- Das Filtern nach Status oder farbliche Darstellung im Frontend war nicht möglich.
Deshalb habe ich einen message handler implementiert.
Message-Klasse
Die Message-Klasse speichert Status und Nachricht.
<?php
namespace MessageHandler;
class Message {
private string $message;
private string $status;
public const SUCCESS = "success";
public const WARNING = "warning";
public const ERROR = "error";
public function __construct(string $message, string $status) {
$this->message = $message;
$this->status = $status;
}
public function getMessage(): string {
return $this->message;
}
public function getStatus(): string {
return $this->status;
}
}
?>MessageHandler-Klasse
Der MessageHandler verwaltet Nachrichten und speichert sie in einem Array.
<?php
namespace MessageHandler;
class MessageHandler {
private array $messages = [];
public function getMessages(): array {
return $this->messages;
}
public function getErrorMessages(): array {
return array_filter($this->messages, fn($m) => $m->getStatus() == Message::ERROR);
}
public function getWarningMessages(): array {
return array_filter($this->messages, fn($m) => $m->getStatus() == Message::WARNING);
}
public function getSuccessMessages(): array {
return array_filter($this->messages, fn($m) => $m->getStatus() == Message::SUCCESS);
}
public function addMessage(string $message, string $status): void {
$this->messages[] = new Message($message, $status);
}
}
?>Auf Anfrage können bestimmte Nachrichten abgerufen werden.
<?php foreach ($messageHandler->getSuccessMessages() as $message): ?>
<p style="font-size: 20px; color: mediumseagreen;"><?= $message->getMessage(); ?></p>
<?php endforeach; ?>Object Relational Mapper (ORM)
ORM speichert Daten aus der Datenbank in Objekten (mapping). Danach kann man CRUD-Operationen über diese Objekte tätigen.
Beispiel
In meinem Projekt habe ich eine Database-Klasse erstellt.
Connect
Will man die MySQL-Datenbank verwenden, kann man die connect-Methode aufrufen.
public function connect() {
$this->mysqli = new mysqli("localhost", "root", "root", "apparel");
}Disconnect
Auch um die Verbindung zu trennen, muss nur die disconnect-Funktion aufgerufen werden.
public function disconnect() {
$this->mysqli->close();
}CRUD
Auch zur Bewältigung von CRUD-Operationen kann man die ORM-Klasse verwenden.
In diesem Beispiel bekommt man die gewünschten Künstler aus der Datenbank.
public function getArtists($ids = null): array {
$artistList = [];
$query = "SELECT * FROM artist" . ($ids ? " WHERE artist_id IN ($ids)" : "");
$artistResponse = $this->mysqli->query($query);
while ($row = $artistResponse->fetch_assoc()) {
$artistList[] = new Artist($row["type"], $row["name"], $row["age"], $row["residence"], $row["nationality"], $row["artist_id"]);
}
return $artistList;
}Hier wird eine Brand gelöscht.
public function deleteBrand(Brand $brand) {
$id = $brand->getId();
$stmt = $this->mysqli->prepare("DELETE FROM brand WHERE brand_id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
}Auf der Zeile 4 wird mithilfe von bind_param die $id in die SQL-Syntax eingefügt, damit diese danach ausgeführt werden kann.