web-dev-qa-db-fra.com

Utilisation d'arguments par défaut dans une fonction

Les valeurs par défaut des fonctions PHP sont confuses. Disons que j'ai une fonction comme celle-ci:

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

Que faire si je veux utiliser l'argument par défaut pour $ x et définir un argument différent pour $ y? 

J'ai expérimenté différentes méthodes et je suis de plus en plus confuse. Par exemple, j'ai essayé ces deux:

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

Mais ces deux éléments ne donnent pas un argument par défaut approprié pour $ x. J'ai aussi essayé de le définir par nom de variable.

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

Je m'attendais vraiment à quelque chose comme ça pour fonctionner. Mais cela ne fonctionne pas comme prévu du tout. Il semble que peu importe ce que je fais, je vais devoir finir par saisir les arguments par défaut, à chaque fois que j'appelle la fonction. Et je dois manquer quelque chose d'évident. 

148
renosis

Je proposerais de changer la déclaration de fonction comme suit afin que vous puissiez faire ce que vous voulez:

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

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

    code here!

}

De cette façon, vous pouvez passer un appel comme foo('blah', null, 'non-default y value'); et le laisser fonctionner à votre guise, le deuxième paramètre $x ayant toujours sa valeur par défaut.

Avec cette méthode, transmettre une valeur null signifie que vous voulez la valeur par défaut pour un paramètre lorsque vous souhaitez remplacer la valeur par défaut pour un paramètre qui le suit.

Comme indiqué dans d'autres réponses, 

les paramètres par défaut ne fonctionnent que comme les derniers arguments de la fonction. Si vous souhaitez déclarer les valeurs par défaut dans la définition de la fonction, il n'y a aucun moyen d'omettre un paramètre et d'en remplacer un qui le suit.

Si j’ai une méthode qui peut accepter un nombre variable de paramètres et des paramètres de types différents, je déclare souvent la fonction similaire à la réponse montrée par Ryan P.

Voici un autre exemple (cela ne répond pas à votre question, mais nous espérons qu'il est informatif:

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!");
    }
}
144
drew010

Les arguments facultatifs ne fonctionnent qu'à la fin d'un appel de fonction. Il n'y a aucun moyen de spécifier une valeur pour $ y dans votre fonction sans spécifier également $ x. Certaines langues supportent cela via des paramètres nommés (VB/C # par exemple), mais pas PHP.

Vous pouvez émuler ceci si vous utilisez un tableau associatif pour les paramètres au lieu d’arguments - c.-à-d.

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

    ...
}

Ensuite, appelez la fonction comme suit:

foo(array('y' => 'my value'));
35
Ryan P

C'est effectivement possible:

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

Si vous voulez le faire est une autre histoire :)


METTRE À JOUR:

Les raisons pour éviter cette solution sont:

  • c'est (sans doute) moche
  • il y a des frais généraux évidents. 
  • comme le prouve l'autre réponse, il existe des alternatives

Mais cela peut être utile dans des situations où:

  • vous ne voulez pas/ne pouvez pas changer la fonction d'origine.
  • vous pouvez changer la fonction mais:

    • utiliser null (ou équivalent) n'est pas une option (voir DiegoDD's comment )
    • vous ne voulez pas aller avec un associatif ou avec func_num_args()
    • votre vie dépend de la sauvegarde de quelques lettres de crédit

En ce qui concerne les performances, un très simple test montre que l'utilisation de l'API Reflection pour obtenir les paramètres par défaut ralentit l'appel de la fonction 25 fois, alors qu'il faut toujours moins d'une microseconde. Vous devriez savoir si vous pouvez vivre avec ça.

Bien sûr, si vous voulez l’utiliser en boucle, vous devez au préalable obtenir la valeur par défaut.

18
David
function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}
10
zloctb

Le seul moyen que je connaisse de le faire est d'omettre le paramètre. Le seul moyen d'omettre le paramètre consiste à réorganiser la liste de paramètres de sorte que celle que vous souhaitez omettre se situe après les paramètres que vous avezDEVEZ DÉFINIR. Par exemple:

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

Ensuite, vous pouvez appeler foo comme:

foo("blah", "test");

Cela se traduira par:

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

J'ai récemment eu ce problème et trouvé cette question et réponses. Bien que les questions ci-dessus fonctionnent, le problème est qu'elles ne montrent pas les valeurs par défaut aux IDE qui le prennent en charge (comme PHPStorm).

 enter image description here

si vous utilisez null, vous ne saurez pas quelle serait la valeur si vous le laissez vide.

La solution que je préfère est de mettre la valeur par défaut dans la définition de la fonction également:

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;
    ...

La seule différence est que je dois m'assurer qu'ils sont identiques - mais je pense que c'est un petit prix à payer pour la clarté supplémentaire.

2
Yehosef

Vous ne pouvez pas le faire directement, mais un peu de code vous permet d’émuler.

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

  // code
}
2
kba

Transmettez un tableau à la fonction, au lieu de paramètres individuels, et utilisez l'opérateur de fusion nul (PHP 7+).

Ci-dessous, je passe un tableau avec 2 éléments. Dans la fonction, je vérifie si la valeur de item1 est définie, si le coffre-fort par défaut n'est pas affecté.

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

    function function_name ($args) {
        isset($args['item1']) ? $args['item1'] : 'default value';
    }
0
Roger
<?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

?>
0
Odin

C'est le cas lorsque l'objet est préférable - car vous pouvez configurer votre objet pour qu'il maintienne x et y, les paramètres par défaut, etc. 

L'approche avec array est proche pour créer un objet (en fait, l'objet est un groupe de paramètres et de fonctions qui fonctionneront sur un objet, et un tableau prenant des fonctions fonctionnera sur certains paramètres d'un tas)

Cerainly vous pouvez toujours faire quelques astuces pour définir null ou quelque chose comme ceci par défaut

0
SergeS