Abschnitt 9 · Lektion 2
composer.json
Jedes Composer-Projekt hat genau eine composer.json, und sie liegt ganz oben im Projektordner.
Sie ist der Ausweis deines Projekts und zugleich seine Einkaufsliste. Anlegen kannst du sie mit
composer init, das dich der Reihe nach fragt, oder mit einem Texteditor. Am Ende ist es JSON, und
JSON kannst du seit Lektion 8.3.
In diesem Kurs nimmst du den Editor. Das Terminal hier gibt einem laufenden Programm keine
Tastatureingabe (help sagt es), composer init fragt dann nichts und schreibt wortlos eine
fast leere Datei über die vorhandene. Der nächste Prüflauf stellt sie wieder her, aber schöner ist
es, gar nicht erst dorthin zu kommen.
Sie ist eine ganz gewöhnliche Datei
{
"name": "hofladen/kasse",
"description": "Kleine Kasse fuer den Hofladen",
"require": {
"php": "^8.2",
"ramsey/uuid": "^4"
},
"require-dev": {
"phpunit/phpunit": "^11"
}
} <?php
// Die composer.json ist ganz gewoehnliches JSON. Wir lesen sie mit
// genau den Mitteln aus Lektion 8.3.
$projekt = json_decode(file_get_contents("composer.json"), true);
echo "Projekt: ", $projekt["name"], "\n";
echo "Zweck: ", $projekt["description"], "\n";
echo "\nBraucht im Betrieb:\n";
foreach ($projekt["require"] as $paket => $bereich) {
echo " ", $paket, " ", $bereich, "\n";
}
echo "\nBraucht nur zum Entwickeln:\n";
foreach ($projekt["require-dev"] as $paket => $bereich) {
echo " ", $paket, " ", $bereich, "\n";
} Bevor wir über die Felder reden, ein Beweis: Das Beispiel liest die composer.json mit
file_get_contents und json_decode, genau wie jede andere Datei im letzten Abschnitt. Nichts
daran ist magisch. Composer liest dieselbe Datei, nur gründlicher.
Zwei Felder stehen hier nebeneinander, und der Unterschied ist wichtig:
requiresind die Pakete, die dein Programm im Betrieb braucht. Ohne sie läuft es nicht.require-devsind die, die nur du beim Entwickeln brauchst. Ein Testwerkzeug gehört hierhin, ein Werkzeug zum Aufräumen von Code auch. Auf dem Server lässt man sie weg, indem man dortcomposer install --no-devaufruft, und das ist der Sinn der Trennung: weniger fremder Code auf der Maschine, die im Netz steht.
phpunit/phpunit steht deshalb unter require-dev, und genau dieses Paket kommt in Abschnitt 17
wieder.
Das Zeichen vor der Versionsnummer
<?php
// Composer entscheidet mit denselben Vergleichen, die PHP eingebaut
// hat. version_compare kennt die Zaehlweise von Versionsnummern.
$kandidaten = ["1.4.1", "1.4.2", "1.4.9", "1.5.0", "1.9.3", "2.0.0"];
printf("%-8s %-8s %-8s %s\n", "Version", "^1.4.2", "~1.4.2", "1.4.*");
foreach ($kandidaten as $version) {
$caret = version_compare($version, "1.4.2", ">=")
&& version_compare($version, "2.0.0", "<");
$tilde = version_compare($version, "1.4.2", ">=")
&& version_compare($version, "1.5.0", "<");
$stern = version_compare($version, "1.4.0", ">=")
&& version_compare($version, "1.5.0", "<");
printf(
"%-8s %-8s %-8s %s\n",
$version,
$caret ? "ja" : "nein",
$tilde ? "ja" : "nein",
$stern ? "ja" : "nein"
);
} "^4" heißt nicht „genau Version 4”. Es ist ein Bereich, und welcher, entscheidet die
semantische Versionierung. Sie ist eine Absprache unter Paketautoren und geht so: Eine Version
besteht aus drei Zahlen, HAUPT.NEBEN.FEHLER.
- Die Fehlernummer steigt bei einer reinen Fehlerbehebung.
- Die Nebennummer steigt, wenn etwas dazukommt, das Bestehende aber weiter funktioniert.
- Die Hauptnummer steigt, wenn etwas kaputtgeht, das vorher funktioniert hat.
Damit kannst du dem Paket sagen, wie mutig es sein darf. Das Beispiel rechnet es mit
version_compare() vor, und die Tabelle liest sich am besten von links nach rechts:
^1.4.2erlaubt alles bis unter die nächste Hauptnummer.1.9.3ist dabei,2.0.0nicht. Das ist die übliche Angabe, und mit ihr bekommst du Fehlerbehebungen ohne Zutun.~1.4.2erlaubt nur bis unter die nächste Nebennummer.1.4.9ist dabei,1.5.0nicht. Vorsichtiger, und manchmal genau richtig.1.4.*ist dasselbe wie~1.4.0, nur anders geschrieben.1.4.2ohne Zeichen heißt: genau diese eine Version, keine andere.
Die Absprache ist eine Absprache und kein Gesetz. Sie hält, weil Paketautoren sie ernst nehmen, und sie hält nicht immer. Deshalb gibt es die zweite Datei, um die es gleich geht.
Die ganze Datei auf einen Blick
{
"name": "hofladen/kasse",
"description": "Kleine Kasse fuer den Hofladen",
"type": "project",
"license": "MIT",
"require": {
"php": "^8.2",
"ramsey/uuid": "^4"
},
"require-dev": {
"phpunit/phpunit": "^11"
},
"autoload": {
"psr-4": {
"Hofladen\\": "src/"
}
},
"scripts": {
"test": "phpunit",
"kasse": "php bin/kasse.php"
}
} Das ist eine vollständige composer.json, wie sie in einem kleinen Projekt aussieht. Sie läuft
nicht, sie ist zum Lesen da. Die Felder der Reihe nach:
nameist immer zweiteilig: Hersteller und Projekt, getrennt durch einen Schrägstrich, alles klein. Auch dein eigenes Projekt braucht ihn, selbst wenn du es nie veröffentlichst.description,typeundlicensesind Angaben über dein Projekt. Wer nichts veröffentlicht, kann sie knapp halten.requireundrequire-devkennst du jetzt.autoloadsagt, wo dein eigener Code liegt und unter welchem Namen er zu finden ist. Das ist Lektion 9.5, und dort wird auch klar, waspsr-4bedeutet und warum hinterHofladenzwei Rückstriche stehen.scriptssind Abkürzungen für Befehle.composer testführt dann aus, was hinterteststeht. Praktisch, sobald ein Befehl länger wird als deine Geduld.
Und die zweite Datei daneben
Sobald du zum ersten Mal etwas installierst, legt Composer eine composer.lock an. Sie hält fest,
welche Version tatsächlich geholt wurde, auf die Ziffer genau, dazu die Stelle im Git des Pakets, aus
der sie stammt, und alles, was die Pakete selbst noch mitgebracht haben. In Lektion 9.3 liegt sie
neben deiner Aufgabe, dann kannst du hineinsehen.
Beide Dateien gehören in die Versionsverwaltung, und das ist keine Geschmacksfrage. Die
composer.json sagt, was erlaubt wäre. Die composer.lock sagt, was bei dir wirklich läuft, und
sorgt dafür, dass auf dem Server exakt dasselbe läuft. Ohne sie steht dort vielleicht 1.9.3,
während bei dir 1.4.2 lief, und der Unterschied fällt an einem Freitagabend auf.
vendor/ gehört dagegen nicht dazu. Der Ordner ist das Ergebnis, die beiden Dateien sind das
Rezept.
Zum Mitnehmen
Eine einzige Datei sagt, was dein Projekt braucht, wie es heißt und wo dein eigener Code liegt. Wer sie lesen kann, versteht ein fremdes PHP-Projekt in zwei Minuten.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, auf dem Server geprüft
Öffnet sich mit dem Basis Konto.