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 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.