Comment ignorer les arguments facultatifs dans un appel de fonction?

94

OK, j'ai totalement oublié comment sauter les arguments en PHP.

Disons que j'ai:

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

Comment appeler cette fonction pour que le paramètre du milieu prenne la valeur par défaut (c'est-à-dire «50»)?

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

Ce qui précède serait-il correct? Je n'arrive pas à faire fonctionner ça.

Chuck Le Butt
la source
1
@Chuck pour que cherchez-vous exactement? Comme une solution de contournement ou une classe pour implémenter ceci ou ...?
Rizier123
@ Rizier123 Je demande à voir si la version actuelle de PHP prend en charge le saut d'arguments (comme le font d'autres langues). Les réponses actuelles peuvent être obsolètes. D'après la description de la prime: "Les réponses actuelles datent de cinq ans. La version actuelle de PHP change-t-elle les choses?"
Chuck Le Butt
1
@Chuck Alors la réponse sera probablement: que rien n'a changé; sans solution de contournement / code, vous n'obtiendrez pas vos fonctionnalités.
Rizier123
Toutes les réponses ici semblent supposer que vous avez le contrôle sur la fonction appelée. Si cette fonction fait partie d'une bibliothèque ou d'un framework, vous n'avez pas d'autre choix que de spécifier quelque chose pour l'argument 2 si vous avez besoin de l'argument 3. La seule option est de rechercher dans la source la fonction et de répliquer la valeur par défaut.
Snapey
Il n'est pas possible de l'ignorer, mais vous pouvez passer l'argument par défaut en utilisant ReflectionFunction. J'ai posté cette réponse dans une question similaire.
David

Réponses:

55

Votre message est correct.

Malheureusement, si vous devez utiliser un paramètre facultatif à la toute fin de la liste de paramètres, vous devez tout spécifier jusqu'à ce dernier paramètre. Généralement, si vous voulez mélanger et assortir, vous leur donnez les valeurs par défaut de ''ou null, et ne les utilisez pas dans la fonction si elles sont cette valeur par défaut.

zombat
la source
1
Pouvez vous donner un exemple?
je suis moi
2
@iamme faire $limit = is_numeric($limit) ? $limit : '50';au début de getData fonction
Kamafeather
40

Il n'y a aucun moyen de "sauter" un argument autre que de spécifier une valeur par défaut comme falseou null.

Comme PHP manque de sucre syntaxique à ce sujet, vous verrez souvent quelque chose comme ceci:

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

Ce qui, comme dit éloquemment dans les commentaires, utilise des tableaux pour émuler des arguments nommés.

Cela donne une flexibilité ultime mais peut ne pas être nécessaire dans certains cas. À tout le moins, vous pouvez déplacer tout ce que vous pensez ne pas être attendu la plupart du temps à la fin de la liste des arguments.

Paolo Bergantino
la source
2
J'identifierais le «quelque chose comme ça» comme «l'utilisation de tableaux pour émuler des arguments nommés», FWIW. :)
chaos
3
En dépit d'être plus flexible, vous devez vous rappeler les paramètres que vous devez / pouvez définir (car ils ne figurent pas dans la signature). Donc, à la fin, cela pourrait ne pas être aussi utile qu'il y paraît, mais cela dépend bien sûr du contexte.
Felix Kling
Alors, quelles seraient les meilleures pratiques pour un tel scénario?
Adam Grant
39

Non, il n'est pas possible de sauter des arguments de cette façon. Vous ne pouvez omettre de transmettre des arguments que s'ils se trouvent à la fin de la liste de paramètres.

Il y avait une proposition officielle à ce sujet: https://wiki.php.net/rfc/skipparams , qui a été refusée. La page de proposition renvoie à d'autres questions SO sur ce sujet.

Cristik
la source
Alors, comment les fonctions PHP ont-elles optionnel de plus / moins de paramètres?
je suis moi
2
PHP prend en charge les valeurs de paramètres par défaut. Mais ces paramètres doivent être à la fin de la liste.
Cristik
1
Vous pouvez trouver des exemples dans la documentation PHP
Cristik
2
Jerks. Ça me rend tellement fou. Si vous n'aimez pas une fonctionnalité que quelqu'un d'autre demande, ne l'utilisez pas. Internet est parfois le pire.
Lee Saxon
@LeeSaxon, le problème est la lisibilité et la portabilité. 1) Si quelqu'un décide d'ignorer des paramètres et que quelqu'un qui débogue le code manque ce fait, une grande confusion se produit. 2) le nouveau code ne pourrait pas fonctionner sur les anciennes versions sans un dépassement majeur et les risques d'erreurs seraient très élevés.
Mark Walsh
6

Rien n'a changé en ce qui concerne la possibilité de sauter des arguments facultatifs, mais pour une syntaxe correcte et pour pouvoir spécifier NULL pour les arguments que je veux ignorer, voici comment je le ferais:

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

Cela peut être appelé ainsi: getData('some name',NULL,'23');et quiconque appellera la fonction à l'avenir n'a pas besoin de se souvenir des valeurs par défaut à chaque fois ou de la constante déclarée pour eux.

Ibrahim Lawal
la source
1
Vous voudriez probablement une comparaison stricte ($ limit === null)
roelleor
4

La réponse simple est non . Mais pourquoi sauter lors de la réorganisation des arguments permet d'atteindre cet objectif?

Le vôtre est une " utilisation incorrecte des arguments de fonction par défaut " et ne fonctionnera pas comme vous le souhaitez.

Une note latérale de la documentation PHP:

Lorsque vous utilisez des arguments par défaut, tous les paramètres par défaut doivent être sur le côté droit de tous les arguments autres que ceux par défaut; sinon, les choses ne fonctionneront pas comme prévu.

Considérer ce qui suit:

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

La sortie sera:

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

L'utilisation correcte des arguments de fonction par défaut devrait être comme ceci:

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

La sortie sera:

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

Mettre la valeur par défaut à votre droite après les non-valeurs par défaut garantit qu'il sera toujours réexécuté la valeur par défaut pour cette variable si elle n'est pas définie / donnée Voici un lien pour référence et d'où viennent ces exemples.

Edit: le définir nullcomme d'autres le suggèrent peut fonctionner et est une autre alternative, mais peut ne pas convenir à ce que vous voulez. Il définira toujours la valeur par défaut sur null s'il n'est pas défini.

Nelson Owalo
la source
C'est la meilleure réponse car elle fournit des explications syntaxiques clairement illustrées! Je vous remercie!
Christian
2

Pour tout paramètre ignoré (vous devez), utilisez le paramètre par défaut, pour être du bon côté.

(Le règlement de null où le paramètre par défaut est `` ou similaire ou vice versa vous posera des problèmes ...)

Frank Nocke
la source
2

Comme mentionné ci-dessus, vous ne pourrez pas ignorer les paramètres. J'ai écrit cette réponse pour fournir un addendum, qui était trop volumineux pour être placé dans un commentaire.

@Frank Nocke propose d'appeler la fonction avec ses paramètres par défaut, donc par exemple avoir

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

Tu devrais utiliser

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

ce qui revient fonctionnellement à omettre les deux premiers paramètres ( $bet $c).

On ne sait pas lesquels sont les valeurs par défaut (est 0 tapé pour fournir la valeur par défaut, ou est-ce important?).

Il existe également un risque que le problème des valeurs par défaut soit lié à une fonction externe (ou intégrée), lorsque les valeurs par défaut pourraient être modifiées par l'auteur de la fonction (ou de la méthode). Donc, si vous ne changez pas votre appel dans le programme, vous pourriez involontairement changer son comportement.

Une solution de contournement pourrait être de définir des constantes globales, comme DEFAULT_A_Bce serait «valeur par défaut du paramètre B de la fonction A» et «omettre» les paramètres de cette façon:

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

Pour les classes, il est plus facile et plus élégant de définir des constantes de classe, car elles font partie de la portée globale, par exemple.

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.

Notez que cette constante par défaut est définie exactement une fois dans tout le code (il n'y a pas de valeur même dans la déclaration de méthode), donc en cas de changements inattendus, vous fournirez toujours la fonction / méthode avec la valeur par défaut correcte.

La clarté de cette solution est bien sûr meilleure que de fournir des valeurs brutes par défaut (comme NULL, 0etc.) qui ne disent rien au lecteur.

(Je suis d'accord qu'appeler comme $var = a(,,'ddd');serait la meilleure option)

Voitcus
la source
2

Vous ne pouvez pas ignorer les arguments, mais vous pouvez utiliser des paramètres de tableau et vous ne devez définir qu'un seul paramètre, qui est un tableau de paramètres.

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

Et vous pouvez ajouter autant de paramètres dont vous avez besoin, vous n'avez pas besoin de les définir. Lorsque vous appelez la fonction, vous mettez vos paramètres comme ceci:

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

Eh bien, comme tout le monde l'a déjà dit, ce que vous voulez ne sera pas possible en PHP sans ajouter de lignes de code dans la fonction.

Mais vous pouvez placer ce morceau de code en haut d'une fonction pour obtenir vos fonctionnalités:

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

Donc, fondamentalement, debug_backtrace()j'obtiens le nom de la fonction dans laquelle ce code est placé, pour ensuite créer un nouveauReflectionFunction objet et une boucle à travers tous les arguments de la fonction.

Dans la boucle, je vérifie simplement si l'argument de la fonction est empty()ET que l'argument est "optionnel" (signifie qu'il a une valeur par défaut). Si oui, j'attribue simplement la valeur par défaut à l'argument.

Demo

Rizier123
la source
0

Définissez la limite sur null

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

et appel à cette fonction

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

si vous souhaitez définir la limite, vous pouvez passer en argument

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

Comme indiqué précédemment , rien n'a changé. Attention, cependant, trop de paramètres (en particulier ceux optionnels) sont un indicateur fort de l'odeur du code.

Peut-être que votre fonction en fait trop:

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

Certains paramètres peuvent être regroupés de manière logique:

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

En dernier recours, vous pouvez toujours introduire un objet paramètre ad-hoc :

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

(qui est juste une version glorifiée de la technique de tableau de paramètres moins formelle )

Parfois, la raison même pour laquelle un paramètre est optionnel est fausse. Dans cet exemple, est-ce $pagevraiment censé être facultatif? L'enregistrement de quelques personnages fait-il vraiment une différence?

// 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
la source
0

Cet extrait:

    function getData ($ name, $ options) {
       $ default = tableau (
            'limite' => 50,
            'page' => 2,
        );
        $ args = array_merge ($ default, $ options);
        print_r ($ args);
    }

    getData ('toto', tableau ());
    getData ('toto', tableau ('limite' => 2));
    getData ('foo', array ('limit' => 10, 'page' => 10));

La réponse est:

     Tableau
    (
        [limite] => 50
        [page] => 2
    )
    Tableau
    (
        [limite] => 2
        [page] => 2
    )
    Tableau
    (
        [limite] => 10
        [page] => 10
    )

personne0jour
la source
2
Agréable. Mais une petite explication serait utile.
showdev
Bonne réponse, mais si vous voulez ignorer le paramètre optionnel, faites-le de cette façon: function getData ($ name, $ args = array ()) {$ defaults = array ('limit': => 50, 'page' => 2) ; $ args = array_merge ($ defaults, $ args); } Il est maintenant possible d'appeler cette fonction avec seulement le premier paramètre comme celui-ci: getData ('foo');
EchoSin
0

Voici ce que je ferais:

<?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 */

?>

J'espère que cela aidera quelqu'un

Michael Eugene Yuen
la source
0

C'est une sorte de vieille question avec un certain nombre de réponses techniquement compétentes, mais elle réclame l'un des modèles de conception modernes de PHP: la programmation orientée objet. Au lieu d'injecter une collection de types de données scalaires primitifs, envisagez d'utiliser un "objet injecté" qui contient toutes les données nécessaires à la fonction. http://php.net/manual/en/language.types.intro.php

L'objet injecté peut avoir des routines de validation de propriété, etc. avec des données potentiellement incomplètes.

Nous pouvons saisir l'objet injecté pour détecter les erreurs avant le déploiement. Certaines des idées sont résumées dans cet article d'il y a quelques années.

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

Ray Paseur
la source
0

J'ai dû créer une usine avec des paramètres optionnels, ma solution de contournement était d'utiliser l'opérateur de fusion nul:

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';
}

Usage:

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

Ce n'est pas la chose la plus jolie, mais pourrait être un bon modèle à utiliser dans les usines pour les tests.

Lucas Bustamante
la source
-1

Essaye ça.

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

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

Vous ne pouvez pas ignorer le paramètre du milieu dans votre appel de fonction. Mais, vous pouvez contourner ceci:

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

Fonction:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}
Ronak Patel
la source
Je ne sais pas pourquoi vous avez des votes négatifs, à part le $ c nécessitant également une valeur par défaut (vous ne pouvez pas avoir d'arguments requis après un argument facultatif).
Frank Forte
-2

Comme l'a souligné @IbrahimLawal. Il est préférable de les définir simplement sur des nullvaleurs. Vérifiez simplement si la valeur passée est celle nulldans laquelle vous utilisez vos valeurs par défaut définies.

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

J'espère que cela t'aides.

asp.patrickg
la source
Vous avez simplement dupliqué la réponse. Vous auriez plutôt pu voter pour ou commenter.
Ibrahim Lawal
-6
getData('some name');

ne les transmettez pas et la valeur par défaut sera acceptée

Shal
la source