vom Positions-Raten zum selbstdokumentierenden Funktionsaufruf
Wer Funktionen und Konstruktoren mit vielen optionalen Parametern aufruft, kennt lange Listen aus true, false und null, deren Bedeutung sich nur durch einen Blick in die Signatur erschließt. Named Arguments lösen dieses Problem, indem der Parametername direkt beim Aufruf sichtbar wird, die Reihenfolge keine Rolle mehr spielt und ungenutzte Defaults nicht künstlich mitgeschrieben werden müssen.
Inhaltsverzeichnis
- 1. Einordnung: Syntax und Zweck von Named Arguments
- 2. Optionale Parameter gezielt überspringen
- 3. Kombination von Positions- und Named Arguments
- 4. Named Arguments und Constructor Property Promotion
- 5. Zusammenspiel mit Variadic-Parametern
- 6. Lesbarkeit bei vielen booleschen Flags
- 7. BC-Fallstricke: Parameter umbenennen
- 8. Named Arguments mit internen PHP-Funktionen
- 9. Best Practices: wann sie sinnvoll sind
- 10. Zusammenfassung
- 11. FAQ
1. Einordnung: Syntax und Zweck von Named Arguments
Seit PHP 8.0 lässt sich jeder Funktions-, Methoden- und Konstruktoraufruf mit der Syntax parameterName: $wert versehen, statt den Wert allein über seine Position in der Argumentliste zuzuordnen. Diese Named Arguments genannte Funktion bindet den übergebenen Wert nicht an die Reihenfolge, sondern an den exakten Namen, den der Parameter in der Funktionssignatur trägt. Entscheidend ist dabei der deklarierte Parametername, nicht der Name der Variablen, die der Aufrufer zufällig verwendet, denn PHP löst die Bindung zur Aufrufzeit gegen die Signatur der aufgerufenen Funktion auf.
Der Zweck dieser Syntax ist in erster Linie Lesbarkeit am Ort des Aufrufs. Ein Aufruf wie createUser('Anna', 'anna@example.com', true, false) verrät nicht, wofür die beiden booleschen Werte stehen, ohne dass man die Signatur von createUser() nachschlägt. Mit benannten Parametern wird derselbe Aufruf zu createUser(name: 'Anna', email: 'anna@example.com', isAdmin: true, sendWelcomeMail: false) und dokumentiert sich damit selbst, ganz ohne zusätzlichen Kommentar im Aufrufercode.
Sie funktionieren bei gewöhnlichen Funktionen, statischen und nicht statischen Methoden, Closures, First-Class-Callables und Konstruktoren gleichermaßen. Named Arguments sind reine Aufruf-Syntax und verändern die Funktionssignatur selbst nicht, weshalb eine bestehende Funktion ohne jede Änderung an ihrer Definition sofort so aufgerufen werden kann, sobald der Aufrufer auf PHP 8.0 oder neuer läuft.
2. Optionale Parameter gezielt überspringen
Der praktische Kernvorteil von Named Arguments zeigt sich bei Funktionen mit mehreren optionalen Parametern. Ohne sie muss ein Aufrufer, der nur den letzten von vier optionalen Parametern setzen will, zwangsläufig auch die drei davor mit ihrem Default-Wert wiederholen, nur um an der Position anzukommen, an der der eigentlich gewünschte Parameter steht. Das führt zu Aufrufen, die den jeweiligen Default explizit ausschreiben, obwohl inhaltlich gar keine Abweichung vom Standardverhalten gewünscht ist.
Mit dieser Aufruf-Syntax entfällt die künstliche Wiederholung vollständig. Der Aufrufer benennt ausschließlich die Parameter, deren Wert tatsächlich vom Default abweichen soll, und überlässt alle anderen ihrem in der Signatur definierten Standardwert. Das reduziert nicht nur die Zeichenanzahl des Aufrufs, sondern macht auch sofort erkennbar, welche Werte für diesen konkreten Aufruf tatsächlich relevant sind, weil alles andere implizit beim Default bleibt.
Wichtig dabei: Ein optionaler Parameter, der übersprungen wird, muss weiterhin einen Default-Wert in der Signatur besitzen. Fehlt der Default und wird der Parameter weder positional noch named befüllt, wirft PHP einen ArgumentCountError, denn Named Arguments ändern nichts an der grundsätzlichen Pflicht, alle Parameter ohne Default zu befüllen.
<?php
declare(strict_types=1);
function createUser(
string $name,
string $email,
bool $isAdmin = false,
bool $sendWelcomeMail = true,
?string $locale = null,
): array {
return compact('name', 'email', 'isAdmin', 'sendWelcomeMail', 'locale');
}
// Only the parameter that actually deviates from its default is named,
// isAdmin and locale simply keep their declared default values
$user = createUser(
name: 'Anna',
email: 'anna@example.com',
sendWelcomeMail: false,
);
3. Kombination von Positions- und Named Arguments
PHP erlaubt es, Positionsargumente und Named Arguments in einem einzigen Aufruf zu mischen, allerdings unter einer festen Regel: Sobald ein Argument benannt übergeben wurde, müssen alle darauffolgenden Argumente ebenfalls benannt sein. Positionsargumente dürfen also nur am Anfang der Argumentliste stehen, danach folgt ausschließlich die benannte Form. Diese Regel verhindert Mehrdeutigkeiten, die entstünden, wenn PHP nach einem benannten Argument wieder auf Positionslogik umschalten müsste.
Ein zweiter zentraler Punkt bei der Kombination: Derselbe Parameter darf niemals doppelt befüllt werden, weder zweimal positional noch einmal positional und einmal benannt. Übergibt ein Aufruf beispielsweise drei Positionsargumente, obwohl der dritte Parameter danach zusätzlich per Namen erneut angesprochen wird, bricht PHP mit einem Error ab, der exakt benennt, welcher Parameter doppelt adressiert wurde. Diese Prüfung erfolgt bereits bei der Argumentauflösung, lange bevor der eigentliche Funktionskörper ausgeführt wird.
In der Praxis bewährt sich die Kombination besonders bei Funktionen, deren erste ein oder zwei Parameter fachlich immer gesetzt werden, während der Rest optional bleibt. Die Pflichtparameter bleiben dann positional kurz und prägnant, während die selten gesetzten optionalen Parameter lesbar benannt werden, ohne dass der komplette Aufruf auf die benannte Form umgestellt werden müsste.
<?php
declare(strict_types=1);
function createUser(
string $name,
string $email,
bool $isAdmin = false,
bool $sendWelcomeMail = true,
?string $locale = null,
): array {
return compact('name', 'email', 'isAdmin', 'sendWelcomeMail', 'locale');
}
// Positional for the two always-required parameters,
// named for everything that deviates from the default
$user = createUser('Anna', 'anna@example.com', sendWelcomeMail: false);
// This raises an Error: "Named parameter $email overwrites previous argument"
// $broken = createUser('Anna', 'anna@example.com', email: 'other@example.com');
4. Named Arguments und Constructor Property Promotion
Constructor Property Promotion und Named Arguments wurden beide mit PHP 8.0 eingeführt und ergänzen sich in der Praxis besonders gut. Ein promoted Constructor-Parameter ist zugleich die Deklaration einer Klasseneigenschaft und ein gewöhnlicher Konstruktorparameter, weshalb er sich exakt wie jeder andere Parameter über seinen Namen ansprechen lässt. Der Parametername im Konstruktor entspricht dabei üblicherweise dem Property-Namen, was den benannten Aufruf besonders lesbar macht, da der Name beim new-Aufruf mit dem späteren Property-Zugriff übereinstimmt.
Gerade bei unveränderlichen Wertobjekten mit readonly-Properties zahlt sich diese Kombination aus. Eine Klasse mit drei oder vier promoted Parametern, von denen nur einer vom Default abweichen soll, profitiert direkt davon: Der Aufrufer muss die Reihenfolge der Konstruktorparameter nicht auswendig kennen und schreibt keine Default-Werte künstlich mit. Das reduziert zugleich das Risiko, zwei benachbarte Parameter gleichen Typs versehentlich zu vertauschen, ein Fehler, der bei rein positionalen Aufrufen mit mehreren int- oder string-Parametern in Folge erfahrungsgemäß häufig passiert.
Bibliotheken, die auf unveränderliche Konfigurationsobjekte setzen, profitieren besonders stark von dieser Kombination: Neue optionale Parameter lassen sich dem Konstruktor am Ende hinzufügen, ohne bestehende Aufrufer zu brechen, solange diese benannte statt reiner Positionsargumente verwenden, denn die Position eines neuen, ans Ende angehängten Parameters betrifft solche Aufrufer schlicht nicht.
<?php
declare(strict_types=1);
final class Money
{
public function __construct(
public readonly int $amount,
public readonly string $currency = 'EUR',
public readonly int $precision = 2,
) {
}
}
// Constructor property promotion plus named arguments:
// only the deviating parameters are spelled out
$price = new Money(amount: 1999, currency: 'USD');
echo sprintf('%d %s', $price->amount, $price->currency);
5. Zusammenspiel mit Variadic-Parametern
Trifft ein Aufruf mit Named Arguments auf eine variadische Funktion mit ...$args, gilt eine eigene Regel: Jedes benannte Argument, dessen Name keinem festen, zuvor deklarierten Parameter entspricht, wird als zusätzlicher Eintrag in das variadische Array aufgenommen, und zwar mit dem Argumentnamen als String-Schlüssel statt einem numerischen Index. Innerhalb der Funktion liegt $args in diesem Fall als assoziatives Array vor, dessen Schlüssel exakt den beim Aufruf verwendeten Parameternamen entsprechen.
Das unterscheidet sich deutlich von einem rein positionalen Aufruf derselben variadischen Funktion, bei dem $args ein numerisch indiziertes Array ist. Ein Funktionskörper, der beide Aufrufarten unterstützen soll, muss deshalb damit rechnen, dass die Schlüssel von $args je nach Aufrufer entweder Integer oder Strings sind, und darf sich nicht blind auf eine der beiden Formen verlassen.
Eng verwandt, aber technisch getrennt zu betrachten ist das Entpacken von Arrays mit String-Schlüsseln über den Spread-Operator, seit PHP 8.1 möglich: foo(...['name' => 'Anna']) übergibt name als benanntes Argument, unabhängig davon, ob foo() selbst variadisch ist. Diese Spread-Syntax erlaubt es, ein zur Laufzeit zusammengestelltes assoziatives Array direkt als Menge benannter Argumente an eine Funktion zu reichen, was besonders bei dynamisch aufgebauten Optionslisten nützlich ist.
<?php
declare(strict_types=1);
function logEvent(string $message, string ...$tags): void
{
// Named arguments beyond the declared $message parameter
// become string keys in the variadic $tags array
foreach ($tags as $key => $value) {
echo "{$key}: {$value}\n";
}
}
logEvent(message: 'Deploy finished', environment: 'production', pipeline: 'release');
// Spreading an associative array into named arguments (PHP 8.1+)
$options = ['environment' => 'staging', 'pipeline' => 'nightly'];
logEvent('Deploy finished', ...$options);
6. Lesbarkeit bei vielen booleschen Flags
Funktionen mit mehreren aufeinanderfolgenden booleschen Parametern gehören zu den Stellen im Code, an denen Named Arguments den größten Lesbarkeitsgewinn bringen. Ein Aufruf wie configure(true, false, true, false) zwingt jeden Leser, in die Signatur von configure() zu schauen, um zu verstehen, welches true für welches Flag steht, und dieser Kontextwechsel kostet bei jedem einzelnen Lesevorgang Zeit. Mit benannten Parametern wird derselbe Aufruf zu configure(cache: true, debug: false, strict: true, verbose: false) und ist ohne jeden Blick in die Definition verständlich.
Dieser Effekt verstärkt sich, sobald mehrere Flags denselben Typ tragen und sich rein positional leicht vertauschen lassen. Zwei benachbarte bool-Parameter mit vertauschter Reihenfolge erzeugen keinen Typfehler, den PHP oder ein Static-Analysis-Tool wie PHPStan zur Compile- beziehungsweise Analysezeit erkennen könnte, weil beide Werte für den Parametertyp gültig sind. Die namensbasierte Zuordnung macht diese Klasse von Fehlern von vornherein unmöglich, weil der Name und nicht die Position darüber entscheidet.
Für Funktionen, die ausschließlich boolesche Flags entgegennehmen, ist der Umstieg im Aufrufercode oft die pragmatischere Lösung gegenüber einem größeren Umbau der Signatur, etwa hin zu einem eigenen Options-Objekt oder Enum-Parametern. Die benannte Form verändert die Funktion selbst nicht und lässt sich deshalb schrittweise im bestehenden Aufrufercode einführen, ohne die Signatur der aufgerufenen Funktion anzufassen.
7. BC-Fallstricke: Parameter umbenennen
Named Arguments machen den Parameternamen einer Funktion zu einem Teil ihrer öffentlichen Schnittstelle, ein Aspekt, der vor PHP 8.0 praktisch irrelevant war. Solange nur positional aufgerufen wurde, konnte ein Parameter beim Refactoring beliebig umbenannt werden, ohne dass ein Aufrufer davon betroffen war. Sobald jedoch irgendein Aufrufer denselben Parameter per Namen anspricht, wird eine scheinbar harmlose Umbenennung zu einem Breaking Change, der sich erst zur Laufzeit als Fehler zeigt.
Konkret wirft PHP in diesem Fall einen Error mit einer Meldung wie „Unknown named parameter“, sobald der Aufrufer den alten, nicht mehr existierenden Parameternamen verwendet. Positionale Aufrufer derselben Funktion bemerken die Umbenennung dagegen überhaupt nicht, solange sich Typ und Reihenfolge der Parameter nicht geändert haben. Diese Asymmetrie bedeutet, dass ein und dieselbe Signaturänderung je nach Aufrufstil völlig unterschiedliche Auswirkungen hat.
Für öffentliche Bibliotheks-APIs folgt daraus eine klare Konsequenz: Parameternamen müssen ab dem Zeitpunkt, an dem sie benannt adressiert werden können, mit derselben Sorgfalt versioniert werden wie Methodennamen selbst. Ein Rename gehört damit in ein Major-Release, nicht in ein Patch- oder Minor-Release, und sollte im Changelog explizit als potenziell brechend für Aufrufer der benannten Form gekennzeichnet werden.
<?php
declare(strict_types=1);
// Public API, version 1.0
final class ImageResizer
{
public function resize(int $width, int $height): void
{
// ...
}
}
$resizer = new ImageResizer();
$resizer->resize(width: 800, height: 600);
// "Harmless" refactoring in version 1.1, positional callers still work fine
final class ImageResizerV2
{
public function resize(int $newWidth, int $newHeight): void
{
// ...
}
}
// Fatal error: Unknown named parameter $width
$broken = (new ImageResizerV2())->resize(width: 800, height: 600);
8. Named Arguments mit internen PHP-Funktionen: Grenzen und Besonderheiten
Seit PHP 8.0 gelten die Parameternamen interner, in C implementierter Funktionen offiziell als Teil der öffentlichen API, sodass Named Arguments auch gegen Funktionen wie htmlspecialchars() oder array_slice() verwendet werden können. Vor dieser Umstellung wurden Parameternamen interner Funktionen gelegentlich zwischen Versionen angepasst, ohne dass dies als Breaking Change galt, weil niemand sie per Namen ansprechen konnte. Diese Freiheit existiert seither nicht mehr in derselben Form.
Einige interne Funktionen mit komplexen Signaturen, etwa solche mit variadischen oder per Referenz übergebenen Parametern, hatten in frühen PHP-8.0-Patch-Releases noch lückenhafte Unterstützung dafür und wurden in nachfolgenden Versionen nachgebessert. Wer benannte Parameter gegen eine interne Funktion einsetzt, sollte deshalb bei älteren, ausgemusterten PHP-Versionen im Zweifel die Handbuchseite der jeweiligen Funktion prüfen, ob und seit welcher Version der dort dokumentierte Parametername stabil ist.
Für den eigenen Code bedeutet das vor allem eines: Diese Syntax gegen interne Funktionen ist erst ab PHP 8.0 aufwärts überhaupt gültig. Ein Codebestand, der noch eine ältere PHP-Version unterstützen muss, kann sie nicht bedingt einsetzen, sondern benötigt für diese Aufrufstellen weiterhin die rein positionale Form, bis die Mindestversion angehoben wird.
| Aufgabe | Nur Positionsargumente | Mit Named Arguments | Vorteil |
|---|---|---|---|
| Mehrere optionale Flags setzen | setOptions(true, false, null, true, 'de') |
setOptions(cache: true, locale: 'de') |
Sofort lesbar, Reihenfolge egal |
| Nur einen mittleren Parameter ändern | Alle Defaults davor mitschreiben | Nur den gewünschten Parameter benennen | Kein künstlicher Boilerplate im Aufruf |
| Einen von vielen optionalen Parametern überspringen | slice($arr, 2, null, true) |
slice($arr, offset: 2, preserveKeys: true) |
Keine null-Platzhalter nötig |
| Konstruktor mit vielen optionalen Properties | Reihenfolge der Parameter auswendig kennen | new Money(amount: 1999, currency: 'USD') |
Selbstdokumentierender Aufruf |
| Mehrere boolesche Flags unterscheiden | create('Anna', true, false, true) |
create(name: 'Anna', isAdmin: false, sendMail: true) |
Vertauschen benachbarter Flags ausgeschlossen |
9. Best Practices: wann sie sinnvoll sind
Named Arguments entfalten den größten Nutzen bei Funktionen und Konstruktoren mit mehreren optionalen Parametern, insbesondere wenn mehrere davon denselben Typ tragen oder rein booleschen Charakter haben. In diesen Fällen überwiegt der Lesbarkeitsgewinn am Aufrufort jeden zusätzlichen Tippaufwand deutlich, und die Gefahr vertauschter, aber typkompatibler Argumente sinkt spürbar. Auch bei selten verwendeten, tief in der Parameterliste stehenden Optionen sind sie fast immer die bessere Wahl gegenüber dem Mitschreiben aller davorliegenden Defaults.
Weniger sinnvoll ist die benannte Form bei Funktionen mit nur ein oder zwei offensichtlichen Pflichtparametern, deren Bedeutung sich bereits aus dem Funktionsnamen und dem Kontext ergibt, etwa strlen($text). Hier fügt sie kaum zusätzliche Klarheit hinzu, verlängert den Aufruf aber unnötig. Ebenso wenig ersetzt sie eine schlecht benannte Signatur: Trägt ein Parameter einen kryptischen oder generischen Namen wie $value oder $data, hilft auch das Benennen beim Aufruf wenig, solange der Name selbst nichts aussagt.
Für öffentliche Bibliotheks-APIs empfiehlt es sich, Parameternamen von Beginn an so sorgfältig zu wählen wie öffentliche Methodennamen, weil sie durch Named Arguments Teil des stabilen Vertrags werden. Innerhalb einer geschlossenen Codebasis, in der alle Aufrufer gemeinsam mit der Signatur weiterentwickelt werden, ist dieses Risiko geringer, doch auch hier lohnt sich Konsistenz, damit benannte Aufrufe über verschiedene Funktionen hinweg vorhersehbar bleiben.
10. Zusammenfassung
Named Arguments lösen ein sehr konkretes Lesbarkeitsproblem: Aufrufe von Funktionen und Konstruktoren mit vielen optionalen Parametern werden vom positionsabhängigen Rätselraten befreit und benennen stattdessen direkt, welcher Wert für welchen Parameter gedacht ist. Optionale Parameter lassen sich gezielt überspringen, Positions- und benannte Argumente kombinieren sich unter klaren Regeln, und die Kombination mit Constructor Property Promotion macht besonders Wertobjekte und Konfigurationsklassen deutlich lesbarer.
Gleichzeitig bringt diese Syntax eine neue Verantwortung mit sich: Der Parametername wird Teil der öffentlichen Schnittstelle einer Funktion, ein Umbenennen beim Refactoring kann Aufrufer mit Named Arguments brechen, auch wenn positionale Aufrufer davon unberührt bleiben. Wer diese Regel kennt, Variadic-Parameter richtig einordnet und die benannte Form gezielt bei vielen optionalen oder booleschen Parametern einsetzt, gewinnt spürbar an Klarheit im Aufrufercode, ohne neue Fehlerquellen zu eröffnen.
Named Arguments in PHP, das Wichtigste auf einen Blick
Syntax
parameterName: $wert bindet den Wert an den deklarierten Parameternamen, unabhängig von der Position im Aufruf.
Kombinieren
Positionsargumente dürfen vorangehen, danach nur noch benannte Argumente. Derselbe Parameter darf nie doppelt befüllt werden.
Variadics
Unbekannte benannte Argumente landen als String-Schlüssel im variadischen Array, statt numerisch indiziert zu sein.
BC-Risiko
Parameternamen sind Teil der öffentlichen API. Umbenennen bricht Aufrufer der benannten Form, positionale Aufrufer bleiben unberührt.
11. FAQ
1Was sind Named Arguments in PHP?
2Seit welcher PHP-Version verfügbar?
3Kombinierbar mit Positionsargumenten?
4Reihenfolge wie in der Signatur nötig?
5Parameter doppelt befüllen?
6Funktionieren sie mit Constructor Promotion?
7Effekt bei Variadic-Parametern?
8Umbenennen ein Breaking Change?
9Unterstützen alle internen Funktionen das?
10Wann darauf verzichten?
Mironsoft
PHP-Architektur, Codequalität und Magento-Entwicklung
Lesbarere Funktionsaufrufe im eigenen Projekt umsetzen?
Wir prüfen bestehenden PHP-Code auf unleserliche Positionsaufrufe und ersetzen sie gezielt durch Named Arguments, mit vollständiger Typsicherheit und PHPStan-Absicherung auf Level 5 und höher.
Code-Review
Analyse unleserlicher Positionsaufrufe und Vorschlag für Named-Arguments-Refactorings
Refactoring
Migration bestehender Konstruktoren und Funktionen zur benannten Aufrufform
PHPStan-Absicherung
Statische Analyse auf Level 5 und höher für neue Named-Arguments-Aufrufe