Verwenden von Standardargumenten in einer Funktion

177

Ich bin verwirrt über die Standardwerte für PHP-Funktionen. Angenommen, ich habe eine Funktion wie diese:

function foo($blah, $x = "some value", $y = "some other value") {
    // code here!
}

Was ist, wenn ich das Standardargument für $ x verwenden und ein anderes Argument für $ y festlegen möchte?

Ich habe mit verschiedenen Methoden experimentiert und bin nur noch verwirrter. Zum Beispiel habe ich diese beiden ausprobiert:

foo("blah", null, "test");
foo("blah", "", "test");

Beides führt jedoch nicht zu einem richtigen Standardargument für $ x. Ich habe auch versucht, es durch Variablennamen festzulegen.

foo("blah", $x, $y = "test");   

Ich habe voll und ganz damit gerechnet, dass so etwas funktioniert. Aber es funktioniert überhaupt nicht so, wie ich es erwartet hatte. Es scheint, als müsste ich, egal was ich tue, die Standardargumente jedes Mal eingeben, wenn ich die Funktion aufrufe. Und mir muss etwas Offensichtliches fehlen.

Renose
quelle
67
Sie vermissen wahrscheinlich nichts, die PHP-Entwickler haben dies wahrscheinlich verpasst.
Matti Virkkunen
Das ist eine interessante Frage. Ich hatte nie die Notwendigkeit, dies zu tun, wie Sie angegeben haben, da ich nur Standardargumente verwende, um Funktionen zu erweitern, die von anderen Programmierern geerbt wurden, wenn ich nicht sicher bin, was vom Original abhängt. Ich bin gespannt auf eine Antwort.
Kai Qing
3
Eine der besten Fragen, die ich seit einiger Zeit gesehen habe! Haben Sie versucht, nichts zu übergeben? foo("blah", , "test");?
Madaras Geist
2
Die Regel ist, dass Standardargumente nur Argumenten folgen können. Das heißt, Sie könnten foo ("blah") und x haben, y sind Standard oder foo ("Blah", "xyz") und y ist der Standard.
Maus Essen
1
Erwartetes Verhalten. Siehe Abschnitt "Standardargumentwerte" in: php.net/manual/en/functions.arguments.php - Nullwert und leere Zeichenfolge werden als tatsächliche Argumente für die Funktion akzeptiert
jmdavalos

Antworten:

164

Ich würde vorschlagen, die Funktionsdeklaration wie folgt zu ändern, damit Sie tun können, was Sie wollen:

function foo($blah, $x = null, $y = null) {
    if (null === $x) {
        $x = "some value";
    }

    if (null === $y) {
        $y = "some other value";
    }

    code here!

}

Auf diese Weise können Sie einen Aufruf wie folgt tätigen foo('blah', null, 'non-default y value');und ihn wie gewünscht arbeiten lassen, wobei der zweite Parameter $ximmer noch seinen Standardwert erhält.

Wenn Sie bei dieser Methode einen Nullwert übergeben, möchten Sie den Standardwert für einen Parameter, wenn Sie den Standardwert für einen nachfolgenden Parameter überschreiben möchten.

Wie in anderen Antworten angegeben,

Standardparameter funktionieren nur als letzte Argumente für die Funktion. Wenn Sie die Standardwerte in der Funktionsdefinition deklarieren möchten, können Sie einen Parameter nicht weglassen und einen darauf folgenden überschreiben.

Wenn ich eine Methode habe, die eine unterschiedliche Anzahl von Parametern und Parameter unterschiedlichen Typs akzeptieren kann, deklariere ich die Funktion häufig ähnlich der Antwort von Ryan P.

Hier ist ein weiteres Beispiel (dies beantwortet Ihre Frage nicht, ist aber hoffentlich informativ:

public function __construct($params = null)
{
    if ($params instanceof SOMETHING) {
        // single parameter, of object type SOMETHING
    } else if (is_string($params)) {
        // single argument given as string
    } else if (is_array($params)) {
        // params could be an array of properties like array('x' => 'x1', 'y' => 'y1')
    } else if (func_num_args() == 3) {
        $args = func_get_args();

        // 3 parameters passed
    } else if (func_num_args() == 5) {
        $args = func_get_args();
        // 5 parameters passed
    } else {
        throw new InvalidArgumentException("Could not figure out parameters!");
    }
}
zog010
quelle
WARUM nicht $ x = isset ($ x)? $ x: 'Standardwert'; ?
Zloctb
@zloctb Dies ist eine saubere und lesbare Nullprüfung. Sieht aus wie es Entwicklerpräferenz ist. Entweder $ x = isset ($ x)? $ x: 'Standardwert'; oder $ x = is_null ($ x)? 'Standardwert': $ x; würde genauso gut funktionieren wie diese Lösung. Es ist eine bevorzugte Wahl in Bezug auf Lesbarkeit und Wartung.
DeveloperWeeks
9
Nur zur Verdeutlichung für zukünftige Leser. Die erste Lösung macht es offensichtlich unmöglich, nulldem Parameter einen realen Wert zuzuweisen , da jedes Mal der Standardwert zugewiesen wird. Selbst wenn Sie einen anderen speziellen Wert hätten, wenn Sie tatsächlich eine Null wollen (z. B. wenn $ x == "use_null" $ x = null macht), könnten Sie keinen solchen speziellen Wert wie den Literalwert von zuweisen Parameter (in diesem Fall die Zeichenfolge "use_null"). Verwenden Sie also unbedingt einen eindeutigen, nie gewünschten "Schlüssel", wenn Sie den Standardwert verwenden möchten (und nulleine gültige Option sein möchten )
DiegoDD
37

Optionale Argumente funktionieren nur am Ende eines Funktionsaufrufs. Es gibt keine Möglichkeit, einen Wert für $ y in Ihrer Funktion anzugeben, ohne auch $ x anzugeben. Einige Sprachen unterstützen dies über benannte Parameter (z. B. VB / C #), jedoch nicht über PHP.

Sie können dies emulieren, wenn Sie ein assoziatives Array für Parameter anstelle von Argumenten verwenden - dh

function foo(array $args = array()) {
    $x = !isset($args['x']) ? 'default x value' : $args['x'];
    $y = !isset($args['y']) ? 'default y value' : $args['y'];

    ...
}

Rufen Sie dann die Funktion folgendermaßen auf:

foo(array('y' => 'my value'));
Ryan P.
quelle
1
Ihre Bedingung sollte wirklich sein isset($args['x']), da sie derzeit eine leere Zeichenfolge, ein leeres Array oder falseden Standardwert ersetzen würde .
Tim Cooper
@TimCooper lol Ich habe aufgrund Ihres ersten Kommentars geändert, dass es '=== null' sein soll, habe meine Antwort geändert, um stattdessen isset zu verwenden, und bin dann zurückgekommen, um zu sehen, dass Sie auch Ihren Kommentar geändert haben. : D
Ryan P
Ah, Trottel! Das gefällt mir überhaupt nicht ... Na ja, man kann nicht alles haben. Dann muss ich wohl etwas mehr über die Reihenfolge meiner Standardargumente nachdenken. Vielen Dank!
Renosis
Leider können Sie mit dieser Antwort keine Null zuweisen. Dies ist eine bessere Option: $x = !array_key_exists('x',$args) ? 'default x value' : $args['x'];
Frank Forte
20

Es ist tatsächlich möglich:

foo( 'blah', (new ReflectionFunction('foo'))->getParameters()[1]->getDefaultValue(), 'test');

Ob du das willst, ist eine andere Geschichte :)


AKTUALISIEREN:

Die Gründe, diese Lösung zu vermeiden, sind:

  • es ist (wohl) hässlich
  • es hat einen offensichtlichen Aufwand.
  • Wie die anderen Antworten beweisen, gibt es Alternativen

Aber es kann tatsächlich in Situationen nützlich sein, in denen:

  • Sie wollen / können die ursprüngliche Funktion nicht ändern.

  • Sie könnten die Funktion ändern, aber:

    • Verwenden null(oder gleichwertig) ist keine Option (siehe Kommentar von DiegoDD )
    • Sie wollen weder mit einem Mitarbeiter noch mit func_num_args()
    • Ihr Leben hängt davon ab, ein paar LOCs zu retten

In Bezug auf die Leistung zeigt ein sehr einfacher Test , dass die Verwendung der Reflection-API zum Abrufen der Standardparameter den Funktionsaufruf 25-mal langsamer macht , während er immer noch weniger als eine Mikrosekunde dauert . Sie sollten wissen, ob Sie damit leben können.

Wenn Sie es in einer Schleife verwenden möchten, sollten Sie natürlich vorher den Standardwert erhalten.

David
quelle
1
Was ist der Grund, dies nicht tun zu wollen? Scheint ziemlich praktisch.
Bryan
10
function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}
zloctb
quelle
2
Vermisse ich etwas Dies scheint die Frage überhaupt nicht zu beantworten, hat aber 7 positive Stimmen. Vielleicht würde es helfen, ein bisschen Erklärung hinzuzufügen?
Sean the Bean
3
@SeantheBean: true, eine Erklärung wäre besser, aber sein Punkt ist: Da PHP keine benannten Argumente hat, verwenden Sie ein assoziatives Array als einzelnen Parameter.
MestreLion
1
Es ist hilfreicher, das in der Frage angegebene Beispiel zu verwenden, z. B.$defaults = [ 'x' => 'some value', 'y' => 'some other value'];
Frank Forte
4

Ich weiß nur, wie ich das mache, indem ich den Parameter weglasse. Die einzige Möglichkeit, den Parameter wegzulassen, besteht darin, die Parameterliste so anzuordnen, dass diejenige, die Sie weglassen möchten, nach den Parametern liegt, die Sie einstellen MÜSSEN . Beispielsweise:

function foo($blah, $y = "some other value", $x = "some value")

Dann können Sie foo wie folgt aufrufen:

foo("blah", "test");

Dies führt zu:

$blah = "blah";
$y = "test";
$x = "some value";
Wes Crow
quelle
3

Ich hatte vor kurzem dieses Problem und fand diese Frage und Antworten. Während die obigen Fragen funktionieren, besteht das Problem darin, dass IDEs, die dies unterstützen (wie PHPStorm), die Standardwerte nicht angezeigt werden.

Geben Sie hier die Bildbeschreibung ein

Wenn Sie verwenden null, wissen Sie nicht, wie hoch der Wert wäre, wenn Sie ihn leer lassen.

Die Lösung, die ich bevorzuge, besteht darin, den Standardwert auch in die Funktionsdefinition aufzunehmen:

protected function baseItemQuery(BoolQuery $boolQuery, $limit=1000, $sort = [], $offset = 0, $remove_dead=true)
{
    if ($limit===null) $limit =1000;
    if ($sort===null) $sort = [];
    if ($offset===null) $offset = 0;
    ...

Der einzige Unterschied ist, dass ich sicherstellen muss, dass sie gleich sind - aber ich denke, das ist ein kleiner Preis für die zusätzliche Klarheit.

Yehosef
quelle
Die interne Verwendung von ReflectionFunction an sich würde den Preis sparen!
SubjectDelta
2

Sie können dies nicht direkt tun, aber ein wenig Code-Fummeln ermöglicht das Emulieren.

function foo($blah, $x = false, $y = false) {
  if (!$x) $x = "some value";
  if (!$y) $y = "some other value";

  // code
}
kba
quelle
6
Das würde funktionieren, aber ich finde die Verwendung nullin diesem Fall konzeptionell ordentlicher als false.
TRiG
Das Hinzufügen zu TriGs Kommentar falseist eine riskantere Wahl als null, da PHP eine nicht strenge Sprache ist. !$xgilt für mehrere verschiedene Eingaben, die den Programmierer überraschen können: 0, ''. Während mit nullkönnen Sie !issetals strengeren Test verwenden.
ToolmakerSteve
1
<?php
function info($name="George",$age=18) {
echo "$name is $age years old.<br>";
}
info();     // prints default values(number of values = 2)
info("Nick");   // changes first default argument from George to Nick
info("Mark",17);    // changes both default arguments' values

?>
Odin
quelle
0

Dies ist der Fall, wenn Objekte besser sind - weil Sie Ihr Objekt so einrichten können, dass es x und y enthält, Standardeinstellungen einrichten usw.

Die Annäherung mit dem Array ist nahe daran, ein Objekt zu erstellen.

Natürlich können Sie immer einige Tricks ausführen, um null oder ähnliches als Standard festzulegen

SergeS
quelle
0

Sie können auch überprüfen, ob Sie eine leere Zeichenfolge als Argument haben, damit Sie Folgendes aufrufen können:

foo('blah', "", 'non-default y value', null);

Unterhalb der Funktion:

function foo($blah, $x = null, $y = null, $z = null) {
    if (null === $x || "" === $x) {
        $x = "some value";
    }

    if (null === $y || "" === $y) {
        $y = "some other value";
    }

    if (null === $z || "" === $z) {
        $z = "some other value";
    }

    code here!

}

Es spielt keine Rolle, ob Sie nulloder füllen "", Sie erhalten immer noch das gleiche Ergebnis.

Mustafa Ekici
quelle
0

Übergeben Sie anstelle einzelner Parameter ein Array an die Funktion und verwenden Sie den Null-Koaleszenz-Operator (PHP 7+).

Unten übergebe ich ein Array mit 2 Elementen. Innerhalb der Funktion überprüfe ich, ob der Wert für item1 festgelegt ist, wenn kein Standardtresor zugewiesen ist.

$args = ['item2' => 'item2',
        'item3' => 'value3'];

    function function_name ($args) {
        isset($args['item1']) ? $args['item1'] : 'default value';
    }
Roger
quelle
Sie können $args['item1'] = $args['item1']??'default value'; in PHP 7+ verwenden. Wenn $ args ['item1'] null ist, wird der default valueString $ args ['item1'] zugewiesen
Sadee
0

Meine 2 Cent mit Null-Koaleszenz-Operator ?? (seit PHP 7)

function foo($blah, $x = null, $y = null) {
    $varX = $x ?? 'Default value X';
    $varY = $y ?? 'Default value Y';
    // ...
}

Sie können weitere Beispiele auf meiner repl.it überprüfen

SandroMarques
quelle