1
0
mirror of https://github.com/php/doc-de.git synced 2026-04-25 07:58:12 +02:00
Files
Martin Samesch af760731c6 Sync with EN
2025-06-12 19:10:30 +02:00

1787 lines
50 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: dd87866772c31671146ff778140dc0955c55005c Maintainer: cmb Status: ready -->
<!-- Reviewed: yes -->
<!-- Rev-Revision: b95e76e41de2ffe5c75e04be1b187d80ca745359 Reviewer: samesch -->
<!-- Credits: hholzgra, tom, updated to fix build by theseer -->
<chapter xml:id="language.functions" xmlns="http://docbook.org/ns/docbook">
<title>Funktionen</title>
<sect1 xml:id="functions.user-defined">
<title>Benutzerdefinierte Funktionen</title>
<para>
Eine Funktion wird definiert mit dem Schlüsselwort
<literal>function</literal>, einem Namen, einer Liste von Parametern (die
auch leer sein können), die durch Kommata (<literal>,</literal>) getrennt
und in Klammern eingeschlossen sind, gefolgt vom Funktionskörper, der in
geschweiften Klammern eingeschlossen ist, wie im folgenden Beispiel:
</para>
<example>
<title>Deklarieren einer neuen Funktion namens <literal>foo</literal></title>
<programlisting role="php">
<![CDATA[
<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
echo "Beispielfunktion.\n";
return $retval;
}
?>
]]>
</programlisting>
</example>
<note>
<para>
Seit PHP 8.0.0 kann die Liste der Parameter ein Komma am Ende enthalten:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
function foo($arg_1, $arg_2,) { }
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
<simpara>
Innerhalb des Funktionskörpers kann jeder beliebige korrekte PHP-Code
vorkommen, sogar andere Funktionen und
<link linkend="language.oop5.basic.class">Klassen</link>-Definitionen.
</simpara>
<para>
Für Funktionsnamen gelten in PHP die gleichen Regeln wie für andere
Bezeichner. Ein gültiger Funktionsname beginnt mit einem Buchstaben oder
Unterstrich gefolgt von einer beliebigen Anzahl von Buchstaben, Ziffern
und Unterstrichen. Als regulärer Ausdruck wird dies so ausgedrückt:
<code>^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$</code>.
</para>
&tip.userlandnaming;
<simpara>
Es ist nicht erforderlich, dass Funktionen bereits definiert sein müssen,
wenn auf sie verwiesen wird, <emphasis>außer</emphasis> wenn eine Funktion
nur bedingt definiert wird, wie in den beiden untenstehenden Beispielen
gezeigt.
</simpara>
<para>
Wenn eine Funktion nur unter bestimmten Bedingungen definiert wird, wie in
den beiden folgenden Beispielen, muss die Definition dieser Funktion noch
<emphasis>vor</emphasis> deren Aufruf abgearbeitet werden.
</para>
<para>
<example>
<title>Bedingte Funktionen</title>
<programlisting role="php">
<![CDATA[
<?php
$makefoo = true;
/* Wir können foo() von hier aus nicht aufrufen, da sie
noch nicht existiert, aber wir können bar() aufrufen */
bar();
if ($makefoo) {
function foo()
{
echo "Ich existiere nicht, bis mich die Programmausführung erreicht hat.\n";
}
}
/* Nun können wir foo() sicher aufrufen,
da $makefoo als true ausgewertet wurde */
if ($makefoo) foo();
function bar()
{
echo "Ich existiere sofort nach Programmstart.\n";
}
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Funktionen innerhalb von Funktionen</title>
<programlisting role="php">
<![CDATA[
<?php
function foo()
{
function bar()
{
echo "Ich existiere nicht, bis foo() aufgerufen wurde.\n";
}
}
/* Wir können bar() noch nicht
aufrufen, da es nicht existiert */
foo();
/* Nun können wir auch bar() aufrufen, da sie durch die
Abarbeitung von foo() verfügbar gemacht wurde */
bar();
?>
]]>
</programlisting>
</example>
</para>
<para>
Alle Funktionen und Klassen in PHP existieren im globalen Namensraum -
sie können außerhalb von Funktionen aufgerufen werden, selbst wenn sie
innerhalb einer Funktion definiert wurden und umgekehrt.
</para>
<simpara>
PHP unterstützt weder das Überladen von Funktionen, noch ist es möglich,
zuvor deklarierte Funktionen neu zu definieren oder die Definition zu
löschen.
</simpara>
<note>
<simpara>
Groß- und Kleinschreibung spielt zwar bei Funktionsnamen keine Rolle für
die ASCII-Zeichen <literal>A</literal> bis <literal>Z</literal>, es
empfiehlt sich aber trotzdem, bei Funktionsaufrufen die gleiche
Schreibweise wie in der Deklaration zu benutzen.
</simpara>
</note>
<simpara>
Sowohl
<link linkend="functions.variable-arg-list">eine variable Anzahl Parameter</link>
als auch
<link linkend="functions.arguments.default">Vorgabewerte für Parameter</link>
werden in Funktionen unterstützt. Siehe auch die Funktionsreferenzen für
<function>func_num_args</function>, <function>func_get_arg</function> und
<function>func_get_args</function> für weitere Informationen.
</simpara>
<para>
Es ist in PHP möglich, Funktionen rekursiv aufzurufen.
<example>
<title>Rekursive Funktionen</title>
<programlisting role="php">
<![CDATA[
<?php
function recursion($a)
{
if ($a < 20) {
echo "$a\n";
recursion($a + 1);
}
}
?>
]]>
</programlisting>
</example>
<note>
<simpara>
Rekursive Funktions-/Methodenaufrufe mit einer Tiefe von über 100-200
können zu einem Stacküberlauf und damit zum Programmabbruch führen.
Insbesondere wird eine unbegrenzte Rekursion als Programmierfehler
erachtet.
</simpara>
</note>
</para>
</sect1>
<sect1 xml:id="functions.arguments">
<title>Funktionsparameter und -argumente</title>
<simpara>
Die Funktionsparameter werden in der Signatur der Funktion deklariert.
Mit einer Liste von Argumenten kann man Informationen an eine Funktion
übergeben. Die Argumentenliste ist eine durch Kommas getrennte Liste von
Ausdrücken. Die Argumente werden von links nach rechts ausgewertet und das
Ergebnis wird den Parametern der Funktion zugewiesen, bevor die eigentliche
Funktion aufgerufen wird, &dh; mit der sog.
<emphasis>eager</emphasis>-Evaluation (dt. eifrige Auswertung).
</simpara>
<para>
PHP unterstützt die Weitergabe von Parametern als Werte (das ist der
Standard), als
<link linkend="functions.arguments.by-reference">Verweise</link> und als
<link linkend="functions.arguments.default">Vorgabewerte</link>. Eine
<link linkend="functions.variable-arg-list">variable Anzahl von Parametern</link>
und <link linkend="functions.named-arguments">benannte Parameter</link> werden
ebenfalls unterstützt.
</para>
<note>
<para>
Seit PHP 7.3.0 ist es möglich, in der Argumentliste eines Funktionsaufrufs
ein nachgestelltes Komma zu verwenden:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$v = foo(
$arg_1,
$arg_2,
);
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
<para>
Seit PHP 8.0.0 kann die Liste der Funktionsparameter ein nachgestelltes
Komma enthalten, das ignoriert wird. Das ist besonders nützlich in Fällen,
in denen die Liste der Parameter lang ist oder lange Variablennamen
enthält, sodass es praktisch ist, die Parameter vertikal aufzulisten.
</para>
<example>
<title>Liste von Funktionsparametern mit nachgestelltem Komma</title>
<programlisting role="php">
<![CDATA[
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // Dieses nachgestellte Komma war vor 8.0.0
// nicht erlaubt.
)
{
// ...
}
?>
]]>
</programlisting>
</example>
<sect2 xml:id="functions.arguments.by-reference">
<title>Parameter als Verweise übergeben</title>
<simpara>
Normalerweise werden den Funktionen Werte als Parameter übermittelt. Wenn
man also den Wert dieser Parameter innerhalb der Funktion ändert, bleiben
sie außerhalb der Funktion unverändert. Wollen Sie aber erreichen, dass
die Änderung auch außerhalb der Funktion sichtbar wird, müssen Sie die
Parameter als Verweise (Referenzen) übergeben.
</simpara>
<para>
Wenn eine Funktion einen Parameter generell als Verweis behandeln soll,
setzt man in der Funktionsdefinition ein kaufmännisches Und (&amp;) vor
den Parameternamen:
</para>
<para>
<example>
<title>Übergeben von Funktionsparametern als Verweis</title>
<programlisting role="php">
<![CDATA[
<?php
function fuege_etwas_an(&$string)
{
$string .= 'und etwas mehr.';
}
$str = 'Dies ist ein String, ';
fuege_etwas_an($str);
echo $str; // Ausgabe: 'Dies ist ein String, und etwas mehr.'
?>
]]>
</programlisting>
</example>
</para>
<para>
Es ist ein Fehler, einen konstanten Ausdruck als Argument an einen
Parameter zu übergeben, der eigentlich als Referenz übergeben werden
müsste.
</para>
</sect2>
<sect2 xml:id="functions.arguments.default">
<title>Vorgabewerte für Parameter</title>
<para>
Eine Funktion kann Standardwerte für Parameter definieren, indem sie eine
ähnliche Syntax wie bei der Zuweisung von Variablen verwendet. Der
Standardwert wird nur verwendet, wenn für den Parameter kein Argument
übergeben wurde. Es ist zu beachten, dass bei der Übergabe von &null;
<emphasis>nicht</emphasis> der Standardwert zugewiesen wird.
</para>
<para>
<example>
<title>Einsatz von Vorgabeparametern in Funktionen</title>
<programlisting role="php">
<![CDATA[
<?php
function machkaffee($typ = "Cappuccino")
{
return "Ich mache eine Tasse $typ.\n";
}
echo machkaffee();
echo machkaffee(null);
echo machkaffee("Espresso");
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Ich mache eine Tasse Cappuccino.
Ich mache eine Tasse .
Ich mache eine Tasse Espresso.
]]>
</screen>
</example>
</para>
<para>
Die Standardwerte der Parameter können skalare Werte,
<type>&array;</type>s, der spezielle Typ &null; und seit PHP 8.1.0 auch
Objekte sein, die die
<link linkend="language.oop5.basic.new">new ClassName()</link>-Syntax
verwenden.
</para>
<para>
<example>
<title>Nichtskalare Typen als Vorgabewert</title>
<programlisting role="php">
<![CDATA[
<?php
function makecoffee($types = array("Cappuccino"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "Hand" : $coffeeMaker;
return "Ich mache eine Tasse ".join(", ", $types)." mit der $device.\n";
}
echo makecoffee();
echo makecoffee(array("Cappuccino", "Lavazza"), "Teekanne");
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Ich mache eine Tasse Cappuccino mit der Hand.
Ich mache eine Tasse Cappuccino, Lavazza mit der Teekanne.
]]>
</screen>
</example>
</para>
<para>
<example>
<title>Verwendung von Objekten als Standardwerte (seit PHP 8.1.0)</title>
<programlisting role="php">
<![CDATA[
<?php
class DefaultCoffeeMaker {
public function brew() {
return "Koche Kaffee.\n";
}
}
class FancyCoffeeMaker {
public function brew() {
return "Bereite einen schönen Kaffee für Dich zu.\n";
}
}
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
{
return $coffeeMaker->brew();
}
echo makecoffee();
echo makecoffee(new FancyCoffeeMaker);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Koche Kaffee.
Bereite einen schönen Kaffee für Dich zu.
]]>
</screen>
</example>
</para>
<simpara>
Der Vorgabewert muss ein konstanter Ausdruck sein, darf also zum Beispiel
keine Variable, keine Eigenschaft einer Klasse und kein Funktionsaufruf
sein.
</simpara>
<para>
Es ist zu beachten, dass optionale Parameter nach den erforderlichen
Parametern angegeben werden müssen, da sie sonst bei einem Aufruf nicht
weggelassen werden können. Das nachfolgende Beispiel verdeutlicht dies:
</para>
<para>
<example>
<title>Ungültige Verwendung von Funktionsparametern mit Vorgabewerten</title>
<programlisting role="php">
<![CDATA[
<?php
function mach_joghurt($typ = "rechtsdrehendes", $geschmack)
{
return "Mache einen Becher $typ $geschmack-Joghurt.\n";
}
echo mach_joghurt("Brombeer"); // "Brombeer" ist $typ, nicht $geschmack
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Fatal error: Uncaught ArgumentCountError: Too few arguments
to function makeyogurt(), 1 passed in example.php on line 42
]]>
</screen>
</example>
</para>
<para>
Zum Vergleich mit obigem Beispiel::
</para>
<para>
<example>
<title>Richtiger Einsatz von Funktionsparametern mit Vorgabewerten</title>
<programlisting role="php">
<![CDATA[
<?php
function mach_joghurt($geschmack, $typ = "rechtsdrehendes")
{
return "Mache einen Becher $typ $geschmack-Joghurt.\n";
}
echo mach_joghurt("Brombeer"); // "Brombeer" ist $geschmack
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Mache einen Becher rechtsdrehendes Brombeer-Joghurt.
]]>
</screen>
</example>
</para>
<para>
Seit PHP 8.0.0 können
<link linkend="functions.named-arguments">benannte Argumente</link>
verwendet werden, um mehrere optionale Parameter zu überspringen.
</para>
<para>
<example>
<title>Korrekte Verwendung von Funktionsparametern mit Vorgabewerten</title>
<programlisting role="php">
<![CDATA[
<?php
function makeyogurt($container = "bowl", $flavour = "raspberry", $style = "Greek")
{
return "Making a $container of $flavour $style yogurt.\n";
}
echo makeyogurt(style: "natural");
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Making a bowl of raspberry natural yogurt.
]]>
</screen>
</example>
</para>
<para>
Seit PHP 8.0.0 wird die Angabe von obligatorischen Parametern nach
optionalen Parametern <emphasis>missbilligt</emphasis>. Dies kann im
Allgemeinen durch das Weglassen des Standardwertes gelöst werden, da er
nie verwendet wird. Eine Ausnahme von dieser Regel sind Parameter der Form
<code>Type $param = null</code>, wobei der Standardwert &null; den Typ
implizit nullbar macht. Diese Verwendung ist seit PHP 8.4.0 veraltet und
stattdessen sollte ein expliziter
<link linkend="language.types.declarations.nullable">nullable Typ</link>
verwendet werden.
<example>
<title>Angabe von optionalen Parametern nach obligatorischen Parametern</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($a = [], $b) {} // Standardwert wird nicht verwendet;
// seit PHP 8.0.0 veraltet
function foo($a, $b) {} // Funktionell identisch, aber ohne Veraltet-Hinweis
function bar(A $a = null, $b) {} // Seit PHP 8.1.0 ist $a implizit erforderlich
// (da es vor dem erforderlichen Parameter steht),
// aber implizit löschbar (seit PHP 8.4.0 veraltet),
// da der Standardparameterwert null ist
function bar(?A $a, $b) {} // Empfohlen
?>
]]>
</programlisting>
</example>
</para>
<note>
<simpara>
Seit PHP 7.1.0 wird ein <classname>ArgumentCountError</classname>
ausgelöst, wenn ein Parameter weggelassen wird, für den kein Standardwert
angegeben ist; in früheren Versionen löste es eine Warnung aus.
</simpara>
</note>
<note>
<simpara>
Parameter, die ein Argument per Verweis erwarten, dürfen einen Standardwert
haben.
</simpara>
</note>
</sect2>
<sect2 xml:id="functions.variable-arg-list">
<title>Variable Anzahl von Argumenten</title>
<simpara>
PHP unterstützt eine variable Anzahl an Argumenten in benutzerdefinierten
Funktionen durch Verwendung des <literal>...</literal>-Tokens.
</simpara>
<para>
Eine Liste von Parametern kann das Token <literal>...</literal>
enthalten, um anzugeben, dass die Funktion eine variable Anzahl von
Argumenten akzeptiert. Die Argumente werden als &array; an die
entsprechende Variable übergeben:
<example>
<title>Verwendung von <literal>...</literal> für den Zugriff auf variable Argumente</title>
<programlisting role="php">
<![CDATA[
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
10
]]>
</screen>
</example>
</para>
<para>
Das Token <literal>...</literal> kann auch dazu verwendet werden, um ein
<type>&array;</type> oder ein <classname>Traversable</classname>-Objekt als
Liste von Argumenten zu übergeben:
<example>
<title>Verwendung von <literal>...</literal> zur Übergabe einer Argumentenliste</title>
<programlisting role="php">
<![CDATA[
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
3
3
]]>
</screen>
</example>
</para>
<para>
Die Definition von regulären, positionierten Parametern vor dem
<literal>...</literal> ist natürlich weiterhin möglich. In einem solchen
Fall werden dann nur die zusätzlichen Werte, die zu keinem positionierten
Parameter gehören, in das durch <literal>...</literal> erzeugte Array
übernommen.
</para>
<para>
Es ist zudem auch möglich, dem <literal>...</literal>-Token eine
<link linkend="language.types.declarations">Typdeklaration</link>
voranzustellen. Ist dies der Fall, dann müssen alle Argumente, die von
<literal>...</literal> erfasst werden, vom entsprechenden Typ sein.
<example>
<title>Variable Argumente mit Typdeklaration</title>
<programlisting role="php">
<![CDATA[
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// Dieser Aufruf wird scheitern, da null keine Instanz von DateInterval ist
echo total_intervals('d', null);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
]]>
</screen>
</example>
</para>
<para>
Durch ein voran gestelltes <literal>&amp;</literal> ist auch die Übergabe
von variablen Argumenten
<link linkend="functions.arguments.by-reference">als Referenz</link>
möglich.
</para>
</sect2>
<sect2 xml:id="functions.named-arguments">
<title>Benannte Argumente</title>
<para>
PHP 8.0.0 führt benannte Argumente als eine Erweiterung der bestehenden
Positionsparameter ein. Benannte Argumente ermöglichen die Übergabe von
Argumenten an eine Funktion basierend auf dem Parameternamen und nicht
auf der Position des Parameters. Das macht die Bedeutung von Argumenten
selbsterklärend, macht die Argumente unabhängig von der Reihenfolge und
ermöglicht das willkürliche Überspringen von Standardwerten.
</para>
<para>
Benannte Argumente werden übergeben, indem dem Wert der Parametername
gefolgt von einem Doppelpunkt vorangestellt wird. Reservierte
Schlüsselwörter dürfen als Parameternamen verwendet werden. Der
Parametername muss ein Bezeichner sein; eine dynamische Angabe ist nicht
erlaubt.
</para>
<example>
<title>Syntax benannter Argumente</title>
<programlisting role="php">
<![CDATA[
<?php
myFunction(paramName: $value);
array_foobar(array: $value);
// Wird NICHT unterstützt
function_name($variableStoringParamName: $value);
?>
]]>
</programlisting>
</example>
<example>
<title>Positionsargumente im Vergleich zu benannten Argumenten</title>
<programlisting role="php">
<![CDATA[
<?php
// Verwendung von Positionsargumenten:
array_fill(0, 100, 50);
// Verwendung von benannten Argumenten:
array_fill(start_index: 0, count: 100, value: 50);
?>
]]>
</programlisting>
</example>
<para>
Die Reihenfolge, in der die benannten Argumente übergeben werden, spielt
keine Rolle.
</para>
<example>
<title>Das gleiche Beispiel wie oben mit einer anderen Reihenfolge der Parameter</title>
<programlisting role="php">
<![CDATA[
<?php
array_fill(value: 50, count: 100, start_index: 0);
?>
]]>
</programlisting>
</example>
<para>
Benannte Argumente können mit Positionsargumenten kombiniert werden. In
diesem Fall müssen die benannten Argumente nach den Positionsargumenten
kommen. Es ist auch möglich, nur einige der optionalen Argumente einer
Funktion anzugeben, unabhängig von ihrer Reihenfolge.
</para>
<example>
<title>Kombinieren von benannten Argumenten mit Positionsargumenten</title>
<programlisting role="php">
<![CDATA[
<?php
htmlspecialchars($string, double_encode: false);
// Ist das Gleiche wie
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>
]]>
</programlisting>
</example>
<para>
Die mehrfache Übergabe eines Arguments an denselben benannten Parameter
führt zu einer <classname>Error</classname>-Exception.
</para>
<example>
<title>Die mehrfache Übergabe eines Arguments an denselben benannten Parameter erzeugt einen Fehler</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($param) { ... }
foo(param: 1, param: 2);
// Error: Named parameter $param overwrites previous argument
foo(1, param: 2);
// Error: Named parameter $param overwrites previous argument
?>
]]>
</programlisting>
</example>
<para>
Seit PHP 8.1.0 ist es möglich, benannte Argumente nach dem Entpacken von
Argumenten zu verwenden. Ein bereits entpacktes Argument
<emphasis>darf nicht</emphasis> durch einen benanntes Argument
überschrieben werden.
</para>
<example>
<title>Verwendung benannter Argumente nach dem Entpacken</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($a, $b, $c = 3, $d = 4) {
return $a + $b + $c + $d;
}
var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46
var_dump(foo(...[1, 2], b: 20)); // Fataler Fehler. Der benannte Parameter $b überschreibt das vorherige Argument
?>
]]>
</programlisting>
</example>
</sect2>
</sect1>
<sect1 xml:id="functions.returning-values">
<title>Rückgabewerte</title>
<para>
Werte können mit der optionalen return-Anweisung zurückgegeben werden. Es
können Variablen jeden Typs zurückgegeben werden, auch Arrays oder
Objekte. Dies beendet die Funktion sofort und die Kontrolle wird wieder an
die aufrufende Zeile zurückgegeben. Für weitere Informationen siehe
<function>return</function>.
</para>
<note>
<para>
Wird <function>return</function> weggelassen, dann wird der Wert &null;
zurückgegeben.
</para>
</note>
<sect2>
<title>Einsatz von return</title>
<para>
<example>
<title>Einsatz von <function>return</function></title>
<programlisting role="php">
<![CDATA[
<?php
function quadrat($zahl)
{
return $zahl * $zahl;
}
echo quadrat(4); // gibt '16' aus.
?>
]]>
</programlisting>
</example>
</para>
<para>
Es ist nicht möglich, mehrere Werte von einer Funktion zurückzugeben. Ein
ähnliches Resultat kann man aber durch die Rückgabe eines Arrays
erreichen.
</para>
<para>
<example>
<title>Rückgabe mehrerer Werte als Array</title>
<programlisting role="php">
<![CDATA[
<?php
function kleine_zahlen()
{
return [0, 1, 2];
}
// Bei der Umstrukturierung von Arrays wird jedes Element des Arrays
// einzeln erfasst.
[$null, $eins, $zwei] = kleine_zahlen();
// Vor 7.1.0 ist die einzige gleichwertige Alternative die Verwendung
// des list()-Konstrukts
list($null, $eins, $zwei) = kleine_zahlen();
?>
]]>
</programlisting>
</example>
</para>
<para>
Um aus einer Funktion eine Referenz zurückzugeben, muss der
Referenz-Operator &amp; sowohl in der Funktionsdeklaration, als auch bei
der Zuweisung des zurückgegebenen Wertes verwendet werden:
</para>
<para>
<example>
<title>Rückgabe von Referenzen aus Funktionen</title>
<programlisting role="php">
<![CDATA[
<?php
function &returniere_referenz()
{
return $einereferenz;
}
$neuereferenz =& returniere_referenz();
?>
]]>
</programlisting>
</example>
</para>
<simpara>
Weitere Informationen über Referenzen sind im Kapitel
<link linkend="language.references">Referenzen in PHP</link> zu finden.
</simpara>
</sect2>
</sect1>
<sect1 xml:id="functions.variable-functions">
<title>Variablenfunktionen</title>
<para>
PHP unterstützt das Konzept der Variablenfunktionen. Wenn Sie an das Ende
einer Variablen Klammern hängen, versucht PHP eine Funktion aufzurufen,
deren Name der aktuelle Wert der Variablen ist. Dies kann unter anderem
für Callbacks, Funktionstabellen usw. genutzt werden.
</para>
<para>
Variablenfunktionen funktionieren nicht mit Sprachkonstrukten wie
<function>echo</function>, <function>print</function>,
<function>unset</function>, <function>isset</function>,
<function>empty</function>, <function>include</function> und
<function>require</function>. Um diese Konstrukte als Variablenfunktionen
benutzen zu können, müssen Sie Ihre eigenen Wrapperfunktionen verwenden.
</para>
<para>
<example>
<title>Beispiel für Variablenfunktionen</title>
<programlisting role="php">
<![CDATA[
<?php
function foo() {
echo "In foo()<br />\n";
}
function bar($arg = '')
{
echo "In bar(); das Argument ist '$arg'.<br />\n";
}
// Dies ist eine Wrapperfunktion für echo
function echoit($string)
{
echo $string;
}
$func = 'foo';
$func(); // Dies ruft foo() auf
$func = 'bar';
$func('test'); // Dies ruft bar() auf
$func = 'echoit';
$func('test'); // Dies ruft echoit() auf
?>
]]>
</programlisting>
</example>
</para>
<para>
Sie können auch die Methode eines Objektes mittels der Variablenfunktionen
aufrufen.
<example>
<title>Beispiel für eine Variablenmethode</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // Dies ruft die Methode Bar() auf
}
function Bar()
{
echo "Das ist Bar";
}
}
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // Dies ruft $foo->Variable() auf
?>
]]>
</programlisting>
</example>
</para>
<para>
Werden statische Methoden aufgerufen, ist der Funktionsaufruf stärker als
der statische Eigenschaftsoperator:
<example>
<title>Beispiel für Variablenmethoden mit statischen Eigenschaften</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
static $variable = 'statische Eigenschaft';
static function Variable()
{
echo 'Method Variable called';
}
}
echo Foo::$variable; // Dies gibt 'statische Eigenschaft' aus. Es bräuchte
// eine $variable im aktuellen Geltungsbereich.
$variable = "Variable";
Foo::$variable(); // Dies ruft $foo->Variable() auf, da $variable im
// aktuellen Geltungsbereich vorliegt.
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Komplexe Callables</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
static function bar()
{
echo "bar\n";
}
function baz()
{
echo "baz\n";
}
}
$func = array("Foo", "bar");
$func(); // gibt "bar" aus
$func = array(new Foo, "baz");
$func(); // gibt "baz" aus
$func = "Foo::bar";
$func(); // gibt "bar" aus
?>
]]>
</programlisting>
</example>
</para>
<sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>is_callable</function></member>
<member><function>call_user_func</function></member>
<member><function>function_exists</function></member>
<member><link linkend="language.variables.variable">Variable Variablen</link></member>
</simplelist>
</para>
</sect2>
</sect1>
<sect1 xml:id="functions.internal">
<title>Interne (eingebaute) Funktionen</title>
<para>
PHP enthält standardmäßig viele Funktionen und Konstrukte. Außerdem gibt
es viele Funktionen die voraussetzen, dass bestimmte PHP-Erweiterungen
einkompiliert wurden, andernfalls erhalten Sie beim Aufruf "undefined
function"-Fehlermeldungen. Um &zb;
<link linkend="ref.image">Grafik-Funktionen</link> wie
<function>imagecreatetruecolor</function> nutzen zu können, müssen Sie PHP
mit <productname>GD</productname>-Unterstützung kompilieren, oder um
<function>mysqli_connect</function> nutzen zu können, muss Ihr PHP mit
<link linkend="book.mysqli">MySQLi</link>-Unterstützung kompiliert sein.
Viele Kernfunktionen, &zb; die
<link linkend="ref.strings">String</link>- und
<link linkend="ref.var">Variablen</link>-Funktionen sind bereits in jeder
PHP-Version enthalten. Ein Aufruf von <function>phpinfo</function> oder
<function>get_loaded_extensions</function> zeigt Ihnen, welche
Erweiterungen in Ihrer PHP-Installation verfügbar sind. Beachten Sie
außerdem, dass viele Erweiterungen bereits standardmäßig aktiviert sind
und das PHP-Handbuch nach Erweiterungen unterteilt ist. Weitere
Informationen zur Einrichtung von PHP finden Sie in den Kapiteln
<link linkend="configuration">Konfiguration</link>,
<link linkend="install">Installation</link> und den Kapiteln zu den
einzelnen Erweiterungen.
</para>
<para>
Wie Funktionsprototypen zu lesen und zu verstehen sind, wird im Kapitel
<link linkend="about.prototypes">Wie man eine Funktionsdefinition (Prototyp) liest</link>
erklärt. Es ist wichtig zu erkennen, was eine Funktion zurückgibt und ob
die übergebenen Parameter verändert werden. So gibt &zb;
<function>str_replace</function> den bearbeiteten String zurück, während
<function>usort</function> die übergebene Variable direkt bearbeitet. Jede
Handbuchseite enthält auch spezifische Informationen zu jeder Funktion, wie
Informationen über ihre Parameter, die Rückgabewerte sowohl bei Erfolg als
auch im Fehlerfall, Änderungen des Verhaltens und die Verfügbarkeit. Die
Kenntnis dieser wichtigen (aber oft subtilen) Unterschiede ist von
entscheidender Bedeutung für das Schreiben korrekten PHP-Codes.
</para>
<note>
<simpara>
Wenn Funktionen andere Parameter erhalten als erwartet, &dh; wenn &zb;
ein <type>&array;</type> übergeben wird, obwohl ein <type>&string;</type>
erwartet wird, so ist der Rückgabewert undefiniert. In solchen Fällen ist
es üblich, dass &null; zurückgegeben wird. Dies ist aber nur eine
Konvention, auf die Sie sich nicht unbedingt verlassen können. Seit
PHP 8.0.0 sollte in diesem Fall eine
<classname>TypeError</classname>-Exception ausgelöst werden.
</simpara>
</note>
<note>
<para>
Bei eingebauten Funktionen sind skalare Typen im erzwingenden Modus
standardmäßig nullbar. Seit PHP 8.1.0 wird in diesem Modus davon
abgeraten, an eine interne Funktion für einen Parameter, der nicht als
nullbar deklariert ist, &null; zu übergeben. Um sich dem Verhalten
benutzerdefinierter Funktionen anzupassen, bei denen skalare Typen
explizit als nullbar deklariert werden müssen, wird in diesem Fall ein
entsprechender Missbilligungs-Hinweis ausgegeben.
</para>
<para>
Zum Beispiel erwartet die Funktion <function>strlen</function>, dass der
Parameter <literal>$string</literal> eine nicht-nullbare Zeichenkette
ist. Aus historischen Gründen erlaubt PHP, für diesen Parameter im
erzwingenden Modus &null; zu übergeben. Der Parameter wird dabei
stillschweigend in den Typ <type>&string;</type> umgewandelt, was den
Wert <literal>""</literal> ergibt. Im Gegensatz dazu wird im strikten
Modus ein <classname>TypeError</classname> ausgegeben.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
var_dump(strlen(null));
// "Deprecated: Passing null to parameter #1 ($string) of type string is deprecated" as of PHP 8.1.0
// int(0)
var_dump(str_contains("foobar", null));
// "Deprecated: Passing null to parameter #2 ($needle) of type string is deprecated" as of PHP 8.1.0
// bool(true)
?>
]]>
</programlisting>
</informalexample>
</note>
<sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>function_exists</function></member>
<member><link linkend="funcref">die Funktionsreferenz</link></member>
<member><function>get_extension_funcs</function></member>
<member><function>dl</function></member>
</simplelist>
</para>
</sect2>
</sect1>
<sect1 xml:id="functions.anonymous">
<title>Anonyme Funktionen</title>
<simpara>
Anonyme Funktionen, auch bekannt als <literal>Closures</literal>,
ermöglichen es, Funktionen ohne Funktionsnamen zu schreiben. Sie sind am
nützlichsten als Werte von <type>callable</type>-Parametern, haben aber
noch viele andere Verwendungsmöglichkeiten.
</simpara>
<simpara>
Anonyme Funktionen werden unter Verwendung der Klasse
<link linkend="class.closure"><classname>Closure</classname></link>
implementiert.
</simpara>
<example>
<title>Beispiel für eine anonyme Funktion</title>
<programlisting role="php">
<![CDATA[
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hallo-welt');
// gibt halloWelt aus
?>
]]>
</programlisting>
</example>
<simpara>
Closures können auch als Werte von Variablen verwendet werden; PHP
konvertiert solche Ausdrücke automatisch in Instanzen der internen Klasse
<classname>Closure</classname>. Die Zuweisung einer Closure an eine
Variable verwendet die selbe Syntax wie andere Zuweisungen, einschließlich
des abschließenden Semikolons:
</simpara>
<example>
<title>Beispiel für die Zuweisung einer anonymen Funktion</title>
<programlisting role="php">
<![CDATA[
<?php
$greet = function($name) {
printf("Hallo %s\r\n", $name);
};
$greet('Welt');
$greet('PHP');
?>
]]>
</programlisting>
</example>
<simpara>
Closures können auch Variablen aus dem Eltern-Gültigkeitsbereich erben.
Jede solche Variable muss an das <literal>use</literal>-Sprachkonstrukt
übergeben werden. Von PHP 7.1 an dürfen diese Variablen keine
&link.superglobals;, <varname>$this</varname> oder Variablen mit dem
gleichen Name wie ein Parameter sein. Die Deklaration des Rückgabetyps der
Funktion muss <emphasis>nach</emphasis> der <literal>use</literal>-Klausel
erfolgen.
</simpara>
<example>
<title>Erben von Variablen aus dem Eltern-Gültigkeitsbereich</title>
<programlisting role="php">
<![CDATA[
<?php
$message = 'hallo';
// Kein "use"
$example = function () {
var_dump($message);
};
$example();
// $message vererben
$example = function () use ($message) {
var_dump($message);
};
$example();
// Der Wert einer geerbten Variable ist der Wert zum Zeitpunkt
// der Funktionsdefinition, nicht des Funktionsaufrufs
$message = 'welt';
$example();
// $message wiederherstellen
$message = 'hallo';
// Vererben per Referenz
$example = function () use (&$message) {
var_dump($message);
};
$example();
// Der geänderte Wert im Eltern-Gültigkeitsbereich
// wird in der aufgerufenen Funktion übernommen
$message = 'welt';
$example();
// Closures können auch reguläre Argumente akzeptieren
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hallo");
// Die Deklaration des Rückgabetyps erfolgt nach der use-Klausel
$example = function () use ($message): string {
return "hallo $message";
};
var_dump($example());
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
Notice: Undefined variable: message in /example.php on line 10
NULL
string(5) "hallo"
string(5) "hallo"
string(5) "hallo"
string(4) "welt"
string(10) "hallo welt"
string(10) "hallo welt"
]]>
</screen>
</example>
<para>
Seit PHP 8.0.0 darf die Liste der geerbten Variablen ein nachgestelltes
Komma enthalten, das ignoriert wird.
</para>
<simpara>
Das Erben von Variablen aus dem Eltern-Gültigkeitsbereich ist
<emphasis>nicht</emphasis> das gleiche wie die Verwendung von globalen
Variablen. Globale Variablen existieren im globalen Gültigkeitsbereich,
der immer der gleiche ist, unabhängig davon, welche Funktion ausgeführt
wird. Der Eltern-Gültigkeitsbereich einer Closure ist die Funktion, in der
die Closure deklariert wurde (nicht notwendigerweise die Funktion, aus der
sie aufgerufen wurde). Betrachten Sie das folgende Beispiel:
</simpara>
<example>
<title>Closures und Gültigkeitsbereiche</title>
<programlisting role="php">
<![CDATA[
<?php
// Ein einfacher Einkaufswagen, der eine Liste von hinzugefügten Produkten
// und die Menge jedes Produkts enthält. Er enthält eine Methode, die den
// Gesamtpreis der Waren im Einkaufswagen unter Verwendung einer Closure
// als Callback berechnet.
class Einkaufswagen
{
const PREIS_BUTTER = 1.00;
const PREIS_MILCH = 3.00;
const PREIS_EIER = 6.95;
protected $produkte = array();
public function addiere($produkt, $menge)
{
$this->produkte[$produkt] = $menge;
}
public function ermittleMenge($produkt)
{
return isset($this->produkte[$produkt]) ? $this->produkte[$produkt] :
FALSE;
}
public function ermittleGesamt($steuer)
{
$gesamt = 0.00;
$callback =
function ($menge, $produkt) use ($steuer, &$gesamt)
{
$preisProStueck = constant(__CLASS__ . "::PREIS_" .
strtoupper($produkt));
$gesamt += ($preisProStueck * $menge) * ($steuer + 1.0);
};
array_walk($this->produkte, $callback);
return round($gesamt, 2);
}
}
$mein_einkaufswagen = new Einkaufswagen;
// Lege ein paar Waren in den Einkaufskorb
$mein_einkaufswagen->addiere('butter', 1);
$mein_einkaufswagen->addiere('milch', 3);
$mein_einkaufswagen->addiere('eier', 6);
// Gib die Gesamtsumme mit einer Mehrwertsteuer von 5% aus
print $mein_einkaufswagen->ermittleGesamt(0.05) . "\n";
// Das Ergebnis ist 54.29
?>
]]>
</programlisting>
</example>
<example>
<title>Automatisches Binden von <literal>$this</literal></title>
<programlisting role="php">
<![CDATA[
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
object(Test)#1 (0) {
}
]]>
</screen>
</example>
<para>
Wird eine anonyme Funktion im Kontext einer Klasse deklariert, so wird
diese Klasse automatisch an jene gebunden, was <literal>$this</literal>
innerhalb des Geltungsbereichs verfügbar macht. Ist diese automatische
Bindung der aktuellen Klasse nicht erwünscht, dann können stattdessen
<link linkend="functions.anonymous-functions.static">statische anonyme Funktionen</link>
verwendet werden.
</para>
<sect2 xml:id="functions.anonymous-functions.static">
<title>Statische anonyme Funktionen</title>
<para>
Anonyme Funktionen können statisch deklariert werden. Dies verhindert,
dass die aktuelle Klasse automatisch an sie gebunden wird. Objekte können
zur Laufzeit ebenfalls nicht an sie gebunden werden.
</para>
<para>
<example>
<title>Versuch der Verwendung von <literal>$this</literal> innerhalb einer statischen anonymen Funktion</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Notice: Undefined variable: this in %s on line %d
NULL
]]>
</screen>
</example>
</para>
<para>
<example>
<title>Versuch, ein Objekt an eine statische anonyme Funktion zu binden</title>
<programlisting role="php">
<![CDATA[
<?php
$func = static function() {
// function body
};
$func = $func->bindTo(new stdClass);
$func();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Warning: Cannot bind an instance to a static closure in %s on line %d
]]>
</screen>
</example>
</para>
</sect2>
<sect2 role="changelog">
&reftitle.changelog;
<para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>8.3.0</entry>
<entry>
Closures, die von
<link linkend="language.oop5.magic">magischen Methoden</link>
erstellt werden, können benannte Parameter akzeptieren.
</entry>
</row>
<row>
<entry>7.1.0</entry>
<entry>
Anonyme Funktionen dürfen &link.superglobals;,
<varname>$this</varname> und alle Variablen mit dem gleichen Namen
wie Parameter nicht als freie Variablen verwenden.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect2>
<sect2 role="notes">
&reftitle.notes;
<note>
<simpara>
Es ist möglich, <function>func_num_args</function>,
<function>func_get_arg</function> und <function>func_get_args</function>
innerhalb einer Closure zu verwenden.
</simpara>
</note>
</sect2>
</sect1>
<sect1 xml:id="functions.arrow">
<title>Pfeilfunktionen</title>
<simpara>
Pfeilfunktionen wurden in PHP 7.4 als prägnantere Syntax für
<link linkend="functions.anonymous">anonyme Funktionen</link> eingeführt.
</simpara>
<simpara>
Sowohl anonyme Funktionen als auch Pfeilfunktionen sind unter Verwendung der
<link linkend="class.closure"><classname>Closure</classname></link>-Klasse
implementiert.
</simpara>
<simpara>
Pfeilfunktionen haben die grundsätzliche Form
<code>fn (argument_list) =&gt; expr</code>.
</simpara>
<simpara>
Pfeilfunktionen unterstützen dieselbe Funktionalität wie
<link linkend="functions.anonymous">anonyme Funktionen</link>,
außer, dass die Verwendung von Variablen des Eltern-Gültigkeitsbereichs
immer automatisch erfolgt.
</simpara>
<simpara>
Wenn eine Variable, die im Ausdruck verwendet wird, im
Eltern-Gültigkeitsbereich definiert ist, wird sie implizit per Wertübergabe
gebunden. Im folgenden Beispiel verhalten sich die Funktionen
<varname>$fn1</varname> und <varname>$fn2</varname> auf die gleiche Weise.
</simpara>
<para>
<example>
<title>Pfeilfunktionen binden Variablen automatisch per Wertübergabe</title>
<programlisting role="php">
<![CDATA[
<?php
$y = 1;
$fn1 = fn($x) => $x + $y;
// gleichwertig zur Verwendung von $y per Wertübergabe:
$fn2 = function ($x) use ($y) {
return $x + $y;
};
var_export($fn1(3));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
4
]]>
</screen>
</example>
</para>
<simpara>
Dies funktioniert auch, wenn Pfeilfunktionen verschachtelt werden:
</simpara>
<para>
<example>
<title>Pfeilfunktionen binden Variablen automatisch per Wertübergabe, selbst wenn sie verschachtelt sind</title>
<programlisting role="php">
<![CDATA[
<?php
$z = 1;
$fn = fn($x) => fn($y) => $x * $y + $z;
// gibt 51 aus
var_export($fn(5)(10));
?>
]]>
</programlisting>
</example>
</para>
<simpara>
Ähnlich wie bei anonymen Funktion erlaubt die Pfeilfunktionssyntax
beliebige Funktionssignaturen, einschließlich Parameter- und
Rückgabetypen, Defaultwerte, variadische Parameter sowie Referenzübergabe
und -rückgabe. Alle folgenden sind gültige Beispiele von Pfeilfunktionen:
</simpara>
<para>
<example>
<title>Beispiele von Pfeilfunktionen</title>
<programlisting role="php">
<![CDATA[
<?php
fn(array $x) => $x;
static fn($x): int => $x;
fn($x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;
?>
]]>
</programlisting>
</example>
</para>
<simpara>
Pfeilfunktionen verwenden die Wertübergabe-Bindung. Dies entspricht in
etwa der Verwendung von <code>use($x)</code> für jede Variable
<varname>$x</varname>, die in der Pfeilfunktion verwendet wird.
Wertübergabe-Bindung bedeutet, dass es nicht möglich ist, Werte aus dem
äußeren Geltungsbereich zu ändern.
<link linkend="functions.anonymous">Anonyme Funktionen</link> können statt
dessen für Referenzübergabe-Bindungen verwendet werden.
</simpara>
<para>
<example>
<title>Werte aus dem äußeren Geltungsbereich können nicht durch Pfeilfunktionen geändert werden</title>
<programlisting role="php">
<![CDATA[
<?php
$x = 1;
$fn = fn() => $x++; // hat keine Wirkung
$fn();
var_export($x); // gibt 1 aus
?>
]]>
</programlisting>
</example>
</para>
<sect2 role="changelog">
&reftitle.changelog;
<para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>7.4.0</entry>
<entry>
Pfeilfunktionen sind verfügbar.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect2>
<sect2 role="notes">
&reftitle.notes;
<note>
<simpara>
Es ist möglich <function>func_num_args</function>,
<function>func_get_arg</function> und <function>func_get_args</function>
innerhalb einer Pfeilfunktion zu verwenden.
</simpara>
</note>
</sect2>
</sect1>
<sect1 xml:id="functions.first_class_callable_syntax">
<title>Callback-Funktionen als Objekte erster Klasse</title>
<para>
Callback-Funktionen als Objekte erster Klasse wurde mit PHP 8.1.0
eingeführt, um
<link linkend="functions.anonymous">anonyme Funktionen</link> aus
<link linkend="language.types.callable" >Callback-Funktionen</link> zu
erstellen. Sie ersetzt die bestehende Callback-Syntax, die Strings und
Arrays verwendet. Der Vorteil dieser Syntax ist, dass sie für die
statische Analyse zugänglich ist und den Gültigkeitsbereich an der Stelle
verwendet, an der die Callback-Funktion aufgerufen wird.
</para>
<para>
Die <code>CallableExpr(...)</code>-Syntax wird verwendet, um ein
<classname>Closure</classname>-Objekt aus einer Callback-Funktion zu
erzeugen. <code>CallableExpr</code> akzeptiert jeden Ausdruck, der in der
PHP-Grammatik direkt aufgerufen werden kann:
<example>
<title>Einfaches Beispiel für eine Callback-Funktion als Objekt erster Klasse</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo {
public function method() {}
public static function staticmethod() {}
public function __invoke() {}
}
$obj = new Foo();
$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';
$f1 = strlen(...);
$f2 = $obj(...); // Callback-Objekt
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// traditionelle Callback-Funktion mit String, Array
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
Das <code>...</code> ist keine Auslassung, sondern Teil der Syntax.
</para>
</note>
<para>
<code>CallableExpr(...)</code> hat die gleiche Semantik wie
<methodname>Closure::fromCallable</methodname>. Das heißt, im Gegensatz zu
Callback-Funktionen, die Strings und Arrays verwenden, wird bei
<code>CallableExpr(...)</code> der Geltungsbereich an dem Punkt
berücksichtigt, an dem er erstellt wird:
<example>
<title>Vergleich des Anwendungsbereichs von <code>CallableExpr(...)</code> und traditionellen Callback-Funktionen</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo {
public function getPrivateMethod() {
return [$this, 'privateMethod'];
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// Dies liegt daran, dass der Aufruf außerhalb von Foo erfolgt und die Sichtbarkeit ab diesem Punkt geprüft wird.
class Foo1 {
public function getPrivateMethod() {
// Verwendet den Bereich, in dem die Callback-Funktion aufgerufen wird.
return $this->privateMethod(...); // identisch mit Closure::fromCallable([$this, 'privateMethod']);
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
Die Erzeugung von Objekten mit dieser Syntax (&zb;
<code>new Foo(...)</code>) wird nicht unterstützt, da die
<code>new Foo()</code>-Syntax nicht als Aufruf betrachtet wird.
</para>
</note>
<note>
<para>
Callback-Funktionen als Objekte erster Klasse können nicht mit dem
<link linkend="language.oop5.basic.nullsafe">Nullsafe-Operator</link>
kombiniert werden. Beides führt zu einem Fehler bei der Kompilierung:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$obj?->method(...);
$obj?->prop->method(...);
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->