Bootstrap
Bootstrap ist der Startcode, der die Umgebung initialisiert, den Dependency Injection (DI) Container erstellt und die Anwendung startet. Wir werden erklären:
- wie sie mithilfe von NEON-Dateien konfiguriert wird
- wie man zwischen Produktions- und Entwicklungsmodus unterscheidet
- wie man den DI-Container erstellt
Anwendungen, egal ob Webanwendungen oder von der Kommandozeile gestartete Skripte, beginnen ihre Ausführung mit einer Form der
Initialisierung der Umgebung. Früher war dafür eine Datei wie include.inc.php
verantwortlich, die von der initialen
Datei eingebunden wurde. In modernen Nette-Anwendungen wurde dies durch die Klasse Bootstrap
ersetzt, die Sie als
Teil der Anwendung in der Datei app/Bootstrap.php
finden. Sie könnte zum Beispiel so aussehen:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
private Configurator $configurator;
private string $rootDir;
public function __construct()
{
$this->rootDir = dirname(__DIR__);
// Der Configurator ist für die Einstellung der Anwendungsumgebung und der Dienste verantwortlich.
$this->configurator = new Configurator;
// Legt das Verzeichnis für temporäre Dateien fest, die von Nette generiert werden (z. B. kompilierte Templates)
$this->configurator->setTempDirectory($this->rootDir . '/temp');
}
public function bootWebApplication(): Nette\DI\Container
{
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}
private function initializeEnvironment(): void
{
// Nette ist schlau und der Entwicklungsmodus wird automatisch aktiviert,
// oder Sie können ihn für eine bestimmte IP-Adresse aktivieren, indem Sie die folgende Zeile auskommentieren:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Aktiviert Tracy: das ultimative "Schweizer Taschenmesser" für das Debugging.
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: lädt automatisch alle Klassen im ausgewählten Verzeichnis
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Lädt Konfigurationsdateien
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
Die initiale Datei für Webanwendungen ist index.php
, die sich im öffentlichen Verzeichnis
www/
befindet. Diese lässt die Umgebung von der Bootstrap-Klasse initialisieren und den DI-Container erstellen.
Danach holt sie sich den Dienst Application
daraus, der die Webanwendung startet:
$bootstrap = new App\Bootstrap;
// Initialisierung der Umgebung + Erstellung des DI-Containers
$container = $bootstrap->bootWebApplication();
// Der DI-Container erstellt das Objekt Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Start der Nette-Anwendung und Verarbeitung der eingehenden Anfrage
$application->run();
Wie man sieht, hilft die Klasse Nette\Bootstrap\Configurator bei der Einstellung der Umgebung und der Erstellung des Dependency Injection (DI) Containers, die wir uns nun genauer ansehen werden.
Entwicklungs- vs. Produktionsmodus
Nette verhält sich unterschiedlich, je nachdem, ob es auf einem Entwicklungs- oder Produktionsserver läuft:
- 🛠️ Entwicklungsmodus (Development)
- Zeigt die Tracy Debugbar mit nützlichen Informationen an (SQL-Abfragen, Ausführungszeit, verwendeter Speicher)
- Zeigt im Fehlerfall eine detaillierte Fehlerseite mit Funktionsaufrufen und Variableninhalten an
- Erneuert automatisch den Cache bei Änderungen an Latte-Templates, Konfigurationsdateien usw.
- 🚀 Produktionsmodus (Production)
- Zeigt keine Debugging-Informationen an, alle Fehler werden im Log protokolliert
- Zeigt im Fehlerfall den ErrorPresenter oder eine allgemeine “Server Error”-Seite an
- Der Cache wird niemals automatisch erneuert!
- Optimiert für Geschwindigkeit und Sicherheit
Die Moduswahl erfolgt durch Auto-Detektion, sodass normalerweise nichts konfiguriert oder manuell umgeschaltet werden muss:
- Entwicklungsmodus: auf Localhost (IP-Adresse
127.0.0.1
oder::1
), wenn kein Proxy vorhanden ist (d. h. dessen HTTP-Header) - Produktionsmodus: überall sonst
Wenn wir den Entwicklungsmodus auch in anderen Fällen aktivieren möchten, z. B. für Programmierer, die von einer bestimmten
IP-Adresse zugreifen, verwenden wir setDebugMode()
:
$this->configurator->setDebugMode('23.75.345.200'); // es kann auch ein Array von IP-Adressen angegeben werden
Wir empfehlen dringend, die IP-Adresse mit einem Cookie zu kombinieren. Wir speichern einen geheimen Token, z. B.
secret1234
, im Cookie nette-debug
und aktivieren auf diese Weise den Entwicklungsmodus für
Programmierer, die von einer bestimmten IP-Adresse zugreifen und gleichzeitig den erwähnten Token im Cookie haben:
$this->configurator->setDebugMode('secret1234@23.75.345.200');
Wir können den Entwicklungsmodus auch vollständig deaktivieren, sogar für Localhost:
$this->configurator->setDebugMode(false);
Achtung, der Wert true
schaltet den Entwicklungsmodus fest ein, was auf einem Produktionsserver niemals
passieren darf.
Debugging-Tool Tracy
Für einfaches Debugging aktivieren wir noch das großartige Werkzeug Tracy. Im Entwicklungsmodus visualisiert es Fehler und im Produktionsmodus protokolliert es Fehler in das angegebene Verzeichnis:
$this->configurator->enableTracy($this->rootDir . '/log');
Temporäre Dateien
Nette verwendet einen Cache für den DI-Container, RobotLoader, Templates usw. Daher ist es notwendig, den Pfad zum Verzeichnis festzulegen, in dem der Cache gespeichert wird:
$this->configurator->setTempDirectory($this->rootDir . '/temp');
Unter Linux oder macOS setzen Sie für die Verzeichnisse log/
und temp/
Schreibrechte.
RobotLoader
In der Regel möchten wir Klassen automatisch mit dem RobotLoader laden,
also müssen wir ihn starten und ihn Klassen aus dem Verzeichnis laden lassen, in dem sich Bootstrap.php
befindet (d.
h. __DIR__
), sowie aus allen Unterverzeichnissen:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Ein alternativer Ansatz besteht darin, Klassen nur über Composer unter Einhaltung von PSR-4 laden zu lassen.
Zeitzone
Über den Konfigurator können Sie die Standard-Zeitzone einstellen.
$this->configurator->setTimeZone('Europe/Prague');
Konfiguration des DI-Containers
Ein Teil des Boot-Prozesses ist die Erstellung des DI-Containers, auch Objektfabrik genannt, der das Herz der gesamten Anwendung ist. Es handelt sich tatsächlich um eine PHP-Klasse, die von Nette generiert und im Cache-Verzeichnis gespeichert wird. Die Fabrik erstellt die Schlüsselobjekte der Anwendung, und mithilfe von Konfigurationsdateien weisen wir sie an, wie sie diese erstellen und einstellen soll, wodurch wir das Verhalten der gesamten Anwendung beeinflussen.
Konfigurationsdateien werden normalerweise im NEON-Format geschrieben. In einem separaten Kapitel erfahren Sie, was alles konfiguriert werden kann.
Im Entwicklungsmodus wird der Container bei jeder Änderung des Codes oder der Konfigurationsdateien automatisch aktualisiert. Im Produktionsmodus wird er nur einmal generiert, und Änderungen werden zur Maximierung der Leistung nicht überprüft.
Konfigurationsdateien laden wir mit addConfig()
:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
Wenn wir mehrere Konfigurationsdateien hinzufügen möchten, können wir die Funktion addConfig()
mehrmals
aufrufen.
$configDir = $this->rootDir . '/config';
$this->configurator->addConfig($configDir . '/common.neon');
$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
$this->configurator->addConfig($configDir . '/cli.php');
}
Der Name cli.php
ist kein Tippfehler; die Konfiguration kann auch in einer PHP-Datei geschrieben sein, die sie als
Array zurückgibt.
Wir können auch weitere Konfigurationsdateien im Abschnitt includes
hinzufügen.
Wenn in den Konfigurationsdateien Elemente mit denselben Schlüsseln erscheinen, werden sie überschrieben oder im Falle von Arrays zusammengeführt. Die später
eingebundene Datei hat eine höhere Priorität als die vorherige. Die Datei, in der der Abschnitt includes
aufgeführt ist, hat eine höhere Priorität als die darin eingebundenen Dateien.
Statische Parameter
Parameter, die in Konfigurationsdateien verwendet werden, können im Abschnitt parameters
definiert und auch über die Methode addStaticParameters()
(hat den Alias addParameters()
) übergeben
(oder überschrieben) werden. Wichtig ist, dass unterschiedliche Werte der Parameter die Generierung zusätzlicher DI-Container,
also zusätzlicher Klassen, verursachen.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
Auf den Parameter projectId
kann in der Konfiguration mit der üblichen Schreibweise %projectId%
verwiesen werden.
Dynamische Parameter
Wir können dem Container auch dynamische Parameter hinzufügen, deren unterschiedliche Werte im Gegensatz zu statischen Parametern nicht die Generierung neuer DI-Container verursachen.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
So können wir einfach z. B. Umgebungsvariablen hinzufügen, auf die dann in der Konfiguration mit der Schreibweise
%env.variable%
verwiesen werden kann.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Standardparameter
In Konfigurationsdateien können Sie diese statischen Parameter verwenden:
%appDir%
ist der absolute Pfad zum Verzeichnis mit der DateiBootstrap.php
%wwwDir%
ist der absolute Pfad zum Verzeichnis mit der Eingabedateiindex.php
%tempDir%
ist der absolute Pfad zum Verzeichnis für temporäre Dateien%vendorDir%
ist der absolute Pfad zum Verzeichnis, in dem Composer Bibliotheken installiert%rootDir%
ist der absolute Pfad zum Stammverzeichnis des Projekts%debugMode%
gibt an, ob sich die Anwendung im Debugging-Modus befindet%consoleMode%
gibt an, ob die Anfrage über die Kommandozeile kam
Importierte Dienste
Jetzt gehen wir tiefer. Obwohl der Zweck des DI-Containers darin besteht, Objekte zu erstellen, kann es ausnahmsweise notwendig
sein, ein vorhandenes Objekt in den Container einzufügen. Dies tun wir, indem wir den Dienst mit dem Flag
imported: true
definieren.
services:
myservice:
type: App\Model\MyCustomService
imported: true
Und im Bootstrap fügen wir das Objekt in den Container ein:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Unterschiedliche Umgebungen
Scheuen Sie sich nicht, die Bootstrap-Klasse an Ihre Bedürfnisse anzupassen. Sie können der Methode
bootWebApplication()
Parameter hinzufügen, um Webprojekte zu unterscheiden. Oder wir können weitere Methoden
hinzufügen, zum Beispiel bootTestEnvironment()
, die die Umgebung für Unit-Tests initialisiert,
bootConsoleApplication()
für Skripte, die von der Kommandozeile aufgerufen werden, usw.
public function bootTestEnvironment(): Nette\DI\Container
{
Tester\Environment::setup(); // Initialisierung von Nette Tester
$this->setupContainer();
return $this->configurator->createContainer();
}
public function bootConsoleApplication(): Nette\DI\Container
{
$this->configurator->setDebugMode(false);
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}