Wie würde ich optionale Argumente in einem Funktionsaufruf überspringen?

94

OK, ich habe völlig vergessen, wie man Argumente in PHP überspringt.

Nehmen wir an, ich habe:

function getData($name, $limit = '50', $page = '1') {
    ...
}

Wie würde ich diese Funktion aufrufen, damit der mittlere Parameter den Standardwert annimmt (dh '50')?

getData('some name', '', '23');

Wäre das oben richtig? Ich kann das scheinbar nicht zum Laufen bringen.

Chuck Le Butt
quelle
1
@Chuck für was suchst du genau? Wie eine Problemumgehung oder eine Klasse, um dies zu implementieren oder ...?
Rizier123
@ Rizier123 Ich frage, ob die aktuelle Version von PHP das Überspringen von Argumenten unterstützt (wie es andere Sprachen tun). Die aktuellen Antworten sind möglicherweise veraltet. Aus der Kopfgeldbeschreibung: "Aktuelle Antworten sind fünf Jahre alt. Ändert die aktuelle Version von PHP etwas?"
Chuck Le Butt
1
@Chuck Dann lautet die Antwort wahrscheinlich: dass sich nichts geändert hat; Ohne Problemumgehung / Code erhalten Sie Ihre Funktionalität nicht.
Rizier123
Alle Antworten hier scheinen davon auszugehen, dass Sie die Kontrolle über die aufgerufene Funktion haben. Wenn diese Funktion Teil einer Bibliothek oder eines Frameworks ist, haben Sie keine andere Wahl, als etwas für Argument 2 anzugeben, wenn Sie Argument 3 benötigen. Die einzige Option besteht darin, in der Quelle nach der Funktion zu suchen und den Standardwert zu replizieren.
Snapey
Es ist nicht möglich, es zu überspringen, aber Sie können das Standardargument mit übergeben ReflectionFunction. Ich habe diese Antwort in einer ähnlichen Frage gepostet .
David

Antworten:

55

Dein Beitrag ist korrekt.

Wenn Sie einen optionalen Parameter ganz am Ende der Parameterliste verwenden müssen, müssen Sie leider alles bis zu diesem letzten Parameter angeben. Wenn Sie mischen und anpassen möchten, geben Sie ihnen im Allgemeinen Standardwerte von ''oder nullund verwenden sie nicht innerhalb der Funktion, wenn es sich um diesen Standardwert handelt.

Zombat
quelle
1
Können Sie ein Beispiel geben?
Ich bin ich
2
@iamme tun $limit = is_numeric($limit) ? $limit : '50';am Anfang der getData- Funktion
Kamafeather
40

Es gibt keine andere Möglichkeit, ein Argument zu "überspringen", als einen Standardwert wie falseoder anzugeben null.

Da es in PHP an syntaktischem Zucker mangelt, werden Sie häufig Folgendes sehen:

checkbox_field(array(
    'name' => 'some name',
    ....
));

Wie in den Kommentaren eloquent gesagt, werden Arrays verwendet, um benannte Argumente zu emulieren.

Dies bietet ultimative Flexibilität, ist jedoch in einigen Fällen möglicherweise nicht erforderlich. Zumindest können Sie alles, was Ihrer Meinung nach die meiste Zeit nicht erwartet wird, an das Ende der Argumentliste verschieben.

Paolo Bergantino
quelle
2
Ich würde das "so etwas" als "Verwenden von Arrays zum Emulieren benannter Argumente", FWIW, identifizieren. :)
Chaos
3
Obwohl Sie flexibler sind, müssen Sie sich die Parameter merken, die Sie einstellen sollten / können (da sie nicht in der Signatur enthalten sind). Am Ende mag es also nicht so nützlich sein, wie es scheint, aber das hängt natürlich vom Kontext ab.
Felix Kling
Was wären die besten Praktiken für ein solches Szenario?
Adam Grant
39

Nein, es ist nicht möglich, Argumente auf diese Weise zu überspringen. Sie können nur übergebene Argumente weglassen dann wenn sie sich am Ende der Parameterliste befinden.

Hierfür gab es einen offiziellen Vorschlag: https://wiki.php.net/rfc/skipparams , der abgelehnt wurde. Die Vorschlagseite enthält Links zu anderen SO-Fragen zu diesem Thema.

Cristik
quelle
Wie haben PHP-Funktionen dann optional mehr / weniger Parameter?
Ich bin ich
2
PHP unterstützt Standardparameterwerte. Diese Parameter müssen jedoch am Ende der Liste stehen.
Cristik
1
Sie finden Beispiele in der PHP-Dokumentation
Cristik
2
Idioten. Macht mich so wütend Wenn Ihnen eine Funktion, die jemand anderes anfordert, nicht gefällt, verwenden Sie sie einfach nicht. Das Internet ist manchmal das Schlimmste.
Lee Saxon
@ LeeSaxon das Problem ist Lesbarkeit und Portabilität. 1) Wenn jemand beschließt, Parameter zu überspringen, und jemand, der Code debuggt, diese Tatsache übersieht, tritt große Verwirrung auf. 2) Neuer Code könnte auf älteren Versionen ohne einen größeren Überholvorgang nicht funktionieren, und die Wahrscheinlichkeit von Fehlern wäre sehr hoch.
Mark Walsh
6

Es hat sich nichts geändert, was das Überspringen optionaler Argumente betrifft, jedoch für die korrekte Syntax und die Angabe von NULL für Argumente, die ich überspringen möchte. So würde ich es machen:

define('DEFAULT_DATA_LIMIT', '50');
define('DEFAULT_DATA_PAGE', '1');

/**
 * getData
 * get a page of data 
 *
 * Parameters:
 *     name - (required) the name of data to obtain
 *     limit - (optional) send NULL to get the default limit: 50
 *     page - (optional) send NULL to get the default page: 1
 * Returns:
 *     a page of data as an array
 */

function getData($name, $limit = NULL, $page = NULL) {
    $limit = ($limit===NULL) ? DEFAULT_DATA_LIMIT : $limit;
    $page = ($page===NULL) ? DEFAULT_DATA_PAGE : $page;
    ...
}

Dies kann so aufgerufen werden: getData('some name',NULL,'23');und jeder, der die Funktion in Zukunft aufruft, muss sich nicht jedes Mal an die Standardeinstellungen oder die für sie deklarierte Konstante erinnern.

Ibrahim Lawal
quelle
1
Sie möchten wahrscheinlich einen strengen Vergleich ($ limit === null)
Roelleor
4

Die einfache Antwort lautet Nein . Aber warum überspringen, wenn die Argumente neu angeordnet werden, um dies zu erreichen?

Ihre ist eine " falsche Verwendung von Standardfunktionsargumenten " und funktioniert nicht so, wie Sie es erwarten.

Eine Randnotiz aus der PHP-Dokumentation:

Bei Verwendung von Standardargumenten sollten sich alle Standardwerte auf der rechten Seite aller nicht standardmäßigen Argumente befinden. Andernfalls funktionieren die Dinge nicht wie erwartet.

Folgendes berücksichtigen:

function getData($name, $limit = '50', $page = '1') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '', '23');   // won't work as expected

Die Ausgabe wird sein:

"Select * FROM books WHERE name = some name AND page = 23 limit"

Die korrekte Verwendung von Standardfunktionsargumenten sollte folgendermaßen aussehen:

function getData($name, $page = '1', $limit = '50') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '23');  // works as expected

Die Ausgabe wird sein:

"Select * FROM books WHERE name = some name AND page = 23 limit 50"

Wenn Sie die Standardeinstellung nach den Nicht-Standardeinstellungen rechts setzen, wird sichergestellt, dass der Standardwert für diese Variable immer neu abgestimmt wird, wenn sie nicht definiert / angegeben ist. Hier ist ein Link als Referenz und woher diese Beispiele stammen.

Bearbeiten: Wenn Sie es nullso einstellen, wie es andere vorschlagen, funktioniert es möglicherweise und ist eine andere Alternative, passt aber möglicherweise nicht zu Ihren Wünschen. Der Standardwert wird immer auf null gesetzt, wenn er nicht definiert ist.

Nelson Owalo
quelle
Dies ist die beste Antwort, da sie klar illustrierte syntaktische Erklärungen liefert! Danke dir!
Christian
2

Für jeden übersprungenen Parameter (Sie müssen) gehen Sie mit dem Standardparameter, um auf der sicheren Seite zu sein.

(Wenn Sie sich für null entscheiden, wenn der Standardparameter '' oder ähnlich ist oder umgekehrt, geraten Sie in Schwierigkeiten ...)

Frank Nocke
quelle
2

Wie oben erwähnt, können Sie keine Parameter überspringen. Ich habe diese Antwort geschrieben, um einen Nachtrag zu liefern, der zu groß war, um ihn in einen Kommentar aufzunehmen.

@Frank Nocke schlägt vor , die Funktion mit ihren Standardparametern aufzurufen, also zum Beispiel mit

function a($b=0, $c=NULL, $d=''){ //...

du solltest benutzen

$var = a(0, NULL, 'ddd'); 

Dies entspricht funktional dem Weglassen der ersten beiden ( $bund $c) Parameter.

Es ist nicht klar, welche 0Standardeinstellungen sind (wird eingegeben, um den Standardwert bereitzustellen, oder ist es wichtig?).

Es besteht auch die Gefahr, dass das Problem mit den Standardwerten mit der externen (oder integrierten) Funktion verbunden ist, wenn die Standardwerte vom Autor der Funktion (oder Methode) geändert werden können. Wenn Sie also Ihren Aufruf im Programm nicht ändern würden, könnten Sie sein Verhalten unbeabsichtigt ändern.

Eine Problemumgehung könnte darin bestehen, einige globale Konstanten zu definieren, z. DEFAULT_A_BB. "Standardwert des B-Parameters der Funktion A" und "Auslassen" der folgenden Parameter:

$var = a(DEFAULT_A_B, DEFAULT_A_C, 'ddd');

Für Klassen ist es einfacher und eleganter, wenn Sie Klassenkonstanten definieren, da diese Teil des globalen Bereichs sind, z.

class MyObjectClass {
  const DEFAULT_A_B = 0;

  function a($b = self::DEFAULT_A_B){
    // method body
  }
} 
$obj = new MyObjectClass();
$var = $obj->a(MyObjectClass::DEFAULT_A_B); //etc.

Beachten Sie, dass diese Standardkonstante im gesamten Code genau einmal definiert wird (selbst in der Methodendeklaration gibt es keinen Wert). Bei unerwarteten Änderungen geben Sie der Funktion / Methode daher immer den korrekten Standardwert an.

Die Klarheit dieser Lösung ist natürlich besser als rohen Standardwert liefert (wie NULL, 0etc.) , die nichts zu einem Leser sagen.

(Ich bin damit einverstanden, dass ein Anruf wie $var = a(,,'ddd');die beste Option wäre)

Voitcus
quelle
2

Sie können keine Argumente überspringen, aber Sie können Array-Parameter verwenden und Sie müssen nur 1 Parameter definieren, bei dem es sich um ein Array von Parametern handelt.

function myfunction($array_param)
{
    echo $array_param['name'];
    echo $array_param['age'];
    .............
}

Und Sie können so viele Parameter hinzufügen, wie Sie benötigen, Sie müssen sie nicht definieren. Wenn Sie die Funktion aufrufen, geben Sie Ihre Parameter folgendermaßen ein:

myfunction(array("name" => "Bob","age" => "18", .........));
Vlad Isoc
quelle
0

Wie alle anderen bereits gesagt haben, ist das, was Sie wollen, in PHP nicht möglich, ohne dass der Funktion Codezeilen hinzugefügt werden.

Sie können diesen Code jedoch oben in eine Funktion einfügen, um Ihre Funktionalität zu erhalten:

foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
    if(empty(${$param->getName()}) && $param->isOptional())
        ${$param->getName()} = $param->getDefaultValue();
}

Also im Grunde mit debug_backtrace()bekomme ich den Funktionsnamen, in den dieser Code gestellt wird, um dann einen neuen zu erstellenReflectionFunction Objekt und alle Funktionsargumente zu durchlaufen.

In der Schleife überprüfe ich einfach, ob das Funktionsargument empty()AND ist und das Argument "optional" ist (bedeutet, dass es einen Standardwert hat). Wenn ja, weise ich dem Argument einfach den Standardwert zu.

Demo

Rizier123
quelle
0

Setzen Sie das Limit auf null

function getData($name, $limit = null, $page = '1') {
    ...
}

und rufen Sie diese Funktion auf

getData('some name', null, '23');

Wenn Sie das Limit festlegen möchten, können Sie es als Argument übergeben

getData('some name', 50, '23');
Hari Kumar
quelle
0

Wie bereits erwähnt , hat sich nichts geändert. Beachten Sie jedoch, dass zu viele Parameter (insbesondere optionale) ein starker Indikator für den Codegeruch sind.

Vielleicht macht Ihre Funktion zu viel:

// first build context
$dataFetcher->setPage(1);
// $dataFetcher->setPageSize(50); // not used here
// then do the job
$dataFetcher->getData('some name');

Einige Parameter können logisch gruppiert werden:

$pagination = new Pagination(1 /*, 50*/);
getData('some name', $pagination);
// Java coders will probably be familiar with this form:
getData('some name', new Pagination(1));

Als letztes Mittel können Sie immer ein Ad-hoc- Parameterobjekt einführen :

$param = new GetDataParameter();
$param->setPage(1);
// $param->setPageSize(50); // not used here
getData($param);

(Dies ist nur eine verherrlichte Version der weniger formalen Parameter-Array- Technik. )

Manchmal ist der Grund, einen Parameter optional zu machen, falsch. Soll in diesem Beispiel $pagewirklich optional sein? Macht das Speichern einiger Zeichen wirklich einen Unterschied?

// dubious
// it is not obvious at first sight that a parameterless call to "getData()"
// returns only one page of data
function getData($page = 1);

// this makes more sense
function log($message, $timestamp = null /* current time by default */);
RandomSeed
quelle
0

Dieser Ausschnitt:

    Funktion getData ($ name, $ options) {
       $ default = array (
            'limit' => 50,
            'Seite' => 2,
        );
        $ args = array_merge ($ default, $ options);
        print_r ($ args);
    }}

    getData ('foo', array ());
    getData ('foo', Array ('limit' => 2));
    getData ('foo', Array ('limit' => 10, 'page' => 10));

Antwort ist :

     Array
    (
        [Grenze] => 50
        [Seite] => 2
    )
    Array
    (
        [limit] => 2
        [Seite] => 2
    )
    Array
    (
        [limit] => 10
        [Seite] => 10
    )

Niemand0Tag
quelle
2
Nett. Aber eine kleine Erklärung wäre hilfreich.
Showdev
Gute Antwort, aber wenn Sie optionale Parameter weglassen möchten, gehen Sie folgendermaßen vor: function getData ($ name, $ args = array ()) {$ defaults = array ('limit': => 50, 'page' => 2) ;; $ args = array_merge ($ defaults, $ args); } Jetzt ist es möglich, diese Funktion nur mit dem ersten Parameter wie diesem aufzurufen: getData ('foo');
EchoSin
0

Das würde ich tun:

<?php

    function getData($name, $limit = '', $page = '1') {
            $limit = (EMPTY($limit)) ? 50 : $limit;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

     echo getData('table');

    /* output name=table&limit=50&page=1 */

     echo getData('table',20);

    /* name=table&limit=20&page=1 */

    echo getData('table','',5);

    /* output name=table&limit=50&page=5 */

    function getData2($name, $limit = NULL, $page = '1') {
            $limit = (ISSET($limit)) ? $limit : 50;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

    echo getData2('table');

    // /* output name=table&limit=50&page=1 */

    echo getData2('table',20);

    /* output name=table&limit=20&page=1 */

    echo getData2('table',NULL,3);

    /* output name=table&limit=50&page=3 */

?>

Hoffe das wird jemandem helfen

Michael Eugene Yuen
quelle
0

Dies ist eine Art alte Frage mit einer Reihe technisch kompetenter Antworten, aber sie verlangt nach einem der modernen Entwurfsmuster in PHP: Objektorientierte Programmierung. Anstatt eine Sammlung primitiver skalarer Datentypen zu injizieren, sollten Sie ein "injiziertes Objekt" verwenden, das alle von der Funktion benötigten Daten enthält. http://php.net/manual/en/language.types.intro.php

Das injizierte Objekt verfügt möglicherweise über Routinen zur Überprüfung von Eigenschaften usw. Wenn die Instanziierung und Injektion von Daten in das injizierte Objekt nicht die gesamte Validierung bestehen kann, kann der Code sofort eine Ausnahme auslösen und die Anwendung kann den umständlichen Prozess des Handels vermeiden mit möglicherweise unvollständigen Daten.

Wir können das injizierte Objekt tippen, um Fehler vor der Bereitstellung abzufangen. Einige der Ideen sind in diesem Artikel von vor einigen Jahren zusammengefasst.

https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html

Ray Paseur
quelle
0

Ich musste eine Factory mit optionalen Parametern erstellen. Meine Problemumgehung bestand darin, den Null-Koaleszenz-Operator zu verwenden:

public static function make(
    string $first_name = null,
    string $last_name = null,
    string $email = null,
    string $subject = null,
    string $message = null
) {
    $first_name = $first_name ?? 'First';
    $last_name  = $last_name ?? 'Last';
    $email      = $email ?? '[email protected]';
    $subject    = $subject ?? 'Some subject';
    $message    = $message ?? 'Some message';
}

Verwendung:

$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');

Nicht das Schönste, aber möglicherweise ein gutes Muster für Tests in Fabriken.

Lucas Bustamante
quelle
-1

Versuche dies.

function getData($name, $limit = NULL, $page = '1') {
               if (!$limit){
                 $limit = 50;
               }
}

getData('some name', '', '23');
Dev Danidhariya
quelle
-2

Sie können den mittleren Parameter in Ihrem Funktionsaufruf nicht überspringen. Aber Sie können damit umgehen:

function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.

Funktion:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}
Ronak Patel
quelle
Ich bin mir nicht sicher, warum Sie Abstimmungen haben, außer dass $ c auch einen Standardwert benötigt (Sie können nach einem optionalen Argument keine erforderlichen Argumente haben).
Frank Forte
-2

Wie @IbrahimLawal betonte. Es wird empfohlen, sie nur auf nullWerte zu setzen. Überprüfen Sie einfach, ob der übergebene Wert der ist, nullin dem Sie Ihre definierten Standardeinstellungen verwenden.

<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);

function getData($name, $limit = null, $page = null) {
    $limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
    $page = is_null($page) ? DEFAULT_PAGE : $page;
    ...
}
?>

Hoffe das hilft.

asp.patrickg
quelle
Sie haben die Antwort einfach dupliziert. Vielmehr hätten Sie es positiv bewerten oder kommentieren können.
Ibrahim Lawal
-6
getData('some name');

Übergeben Sie sie einfach nicht und der Standardwert wird akzeptiert

Shal
quelle