¿Cómo omitiría argumentos opcionales en una llamada a función?

94

De acuerdo, olvidé por completo cómo omitir argumentos en PHP.

Digamos que tengo:

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

¿Cómo llamaría a esta función para que el parámetro del medio tome el valor predeterminado (es decir, '50')?

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

¿Sería correcto lo anterior? Parece que no puedo hacer que esto funcione.

Chuck Le Butt
fuente
1
@Chuck, ¿qué estás buscando exactamente? ¿Como una solución alternativa o una clase para implementar esto o ...?
Rizier123
@ Rizier123 Estoy preguntando si la versión actual de PHP admite la omisión de argumentos (como lo hacen otros lenguajes). Las respuestas actuales pueden estar desactualizadas. De la descripción de la recompensa: "Las respuestas actuales tienen cinco años. ¿La versión actual de PHP cambia las cosas?"
Chuck Le Butt
1
@Chuck Entonces la respuesta probablemente será: que nada cambió; sin una solución / código, no obtendrá su funcionalidad.
Rizier123
Todas las respuestas aquí parecen asumir que tiene control sobre la función que se llama. Si esa función es parte de una biblioteca o marco, no tiene más opción que especificar algo para el argumento 2 si necesita el argumento 3. La única opción es buscar en la fuente la función y replicar el valor predeterminado.
Snapey
No es posible omitirlo, pero puede pasar el argumento predeterminado usando ReflectionFunction. Publiqué esa respuesta en una pregunta similar.
David

Respuestas:

55

Tu publicación es correcta.

Desafortunadamente, si necesita usar un parámetro opcional al final de la lista de parámetros, debe especificar todo hasta el último parámetro. En general, si desea mezclar y combinar, les da valores predeterminados de'' o nully no los use dentro de la función si son ese valor predeterminado.

zombat
fuente
1
¿Puede dar un ejemplo?
yo soy yo
2
@iamme hacer $limit = is_numeric($limit) ? $limit : '50';al comienzo de getData función
Kamafeather
40

No hay forma de "omitir" un argumento que no sea especificar un me gusta falseonull .

Dado que PHP carece de algo de azúcar sintáctico cuando se trata de esto, a menudo verá algo como esto:

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

Lo cual, como se dijo elocuentemente en los comentarios, está usando matrices para emular argumentos con nombre.

Esto proporciona la máxima flexibilidad, pero puede que no sea necesario en algunos casos. Como mínimo, puede mover lo que crea que no se espera la mayor parte del tiempo al final de la lista de argumentos.

Paolo Bergantino
fuente
2
Identificaría 'algo como esto' como 'usar matrices para emular argumentos con nombre', FWIW. :)
caos
3
A pesar de ser más flexible, debe recordar los parámetros que debe / puede establecer (ya que no están en la firma). Entonces, al final, puede que no sea tan útil como parece, pero por supuesto esto depende del contexto.
Felix Kling
Entonces, ¿cuáles serían las mejores prácticas para tal escenario?
Adam Grant
39

No, no es posible omitir argumentos de esta manera. Puede omitir el paso de argumentos solo si están al final de la lista de parámetros.

Hubo una propuesta oficial para esto: https://wiki.php.net/rfc/skipparams , que fue rechazada. La página de la propuesta enlaza con otras preguntas de SO sobre este tema.

Cristik
fuente
Entonces, ¿cómo tienen las funciones PHP opcionales de más / menos parámetros?
yo soy yo
2
PHP tiene soporte para valores de parámetros predeterminados. Pero esos parámetros deben estar al final de la lista.
Cristik
1
Puede encontrar ejemplos en la documentación de PHP
Cristik
2
Tirones. Me enoja tanto. Si no le gusta una función que solicite otra persona, simplemente no la use. Internet es lo peor a veces.
Lee Saxon
@LeeSaxon, el problema es la legibilidad y la portabilidad. 1) Si alguien decide saltarse los parámetros y alguien que depura el código no lo hace, se produce una gran confusión. 2) el código nuevo no podría funcionar en versiones anteriores sin una revisión importante y las posibilidades de errores serían muy altas.
Mark Walsh
6

Nada ha cambiado con respecto a poder omitir argumentos opcionales, sin embargo, para una sintaxis correcta y poder especificar NULL para los argumentos que quiero omitir, así es como lo haría:

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

Esto se puede llamar así: getData('some name',NULL,'23');y cualquiera que llame a la función en el futuro no necesita recordar los valores predeterminados cada vez o la constante declarada para ellos.

Ibrahim Lawal
fuente
1
Probablemente desee una comparación estricta ($ limit === null)
roelleor
4

La respuesta simple es no . Pero, ¿por qué saltarse cuando reorganizar los argumentos logra esto?

El suyo es un " Uso incorrecto de los argumentos de función predeterminados " y no funcionará como espera.

Una nota al margen de la documentación de PHP:

Cuando se utilizan argumentos predeterminados, los valores predeterminados deben estar en el lado derecho de los argumentos no predeterminados; de lo contrario, las cosas no funcionarán como se esperaba.

Considera lo siguiente:

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 salida será:

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

El uso correcto de los argumentos de la función predeterminada debería ser así:

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 salida será:

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

Poner el valor predeterminado a su derecha después de los valores no predeterminados asegura que siempre devolverá el valor predeterminado para esa variable si no está definido / dado Aquí hay un enlace para referencia y de dónde provienen esos ejemplos.

Editar: configurarlo nullcomo otros sugieren podría funcionar y es otra alternativa, pero es posible que no se adapte a lo que desea. Siempre establecerá el valor predeterminado en nulo si no está definido.

Nelson Owalo
fuente
¡Esta es la mejor respuesta ya que proporciona explicaciones sintácticas claramente ilustradas! ¡Gracias!
Christian
2

Para cualquier parámetro omitido (debe hacerlo), vaya con el parámetro predeterminado, para estar seguro.

(Establecer un valor nulo donde el parámetro predeterminado es '' o similar o viceversa lo meterá en problemas ...)

Frank Nocke
fuente
2

Como se mencionó anteriormente, no podrá omitir parámetros. Escribí esta respuesta para proporcionar un apéndice, que era demasiado grande para incluirlo en un comentario.

@Frank Nocke propone llamar a la función con sus parámetros predeterminados, por ejemplo, tener

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

Deberías usar

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

que funcionalmente será lo mismo que omitir los dos primeros ( $by$c ) parámetros.

No está claro cuáles son los predeterminados (se 0escribe para proporcionar un valor predeterminado, ¿o es importante?).

También existe el peligro de que el problema de valores predeterminados esté conectado a una función externa (o incorporada), cuando el autor de la función (o método) podría cambiar los valores predeterminados. Entonces, si no cambia su llamada en el programa, podría cambiar involuntariamente su comportamiento.

Una solución podría ser definir algunas constantes globales, como las DEFAULT_A_Bque serían "valor predeterminado del parámetro B de la función A" y "omitir" parámetros de esta manera:

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

Para las clases, es más fácil y elegante definir las constantes de clase, porque son parte del alcance global, por ejemplo.

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.

Tenga en cuenta que esta constante predeterminada se define exactamente una vez en todo el código (no hay ningún valor incluso en la declaración del método), por lo que en caso de algunos cambios inesperados, siempre proporcionará la función / método con el valor predeterminado correcto.

La claridad de esta solución es, por supuesto, mejor que proporcionar valores predeterminados sin procesar (como NULL, 0etc.) que no le dicen nada al lector.

(Estoy de acuerdo en que llamar como $var = a(,,'ddd');sería la mejor opción)

Voitcus
fuente
2

No puede omitir argumentos, pero puede usar parámetros de matriz y debe definir solo 1 parámetro, que es una matriz de parámetros.

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

Y puede agregar tantos parámetros como necesite, no es necesario que los defina. Cuando llamas a la función, pones tus parámetros así:

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

Bueno, como todos los demás ya han dicho, lo que quieres no será posible en PHP sin agregar líneas de código en la función.

Pero puede colocar este fragmento de código en la parte superior de una función para obtener su funcionalidad:

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

Básicamente debug_backtrace(), obtengo el nombre de la función en la que se coloca este código, para luego crear un nuevo ReflectionFunctionobjeto y recorrer todos los argumentos de la función.

En el ciclo, simplemente verifico si el argumento de la función es empty()Y el argumento es "opcional" (significa que tiene un valor predeterminado). Si es así, simplemente asigno el valor predeterminado al argumento.

Demo

Rizier123
fuente
0

Establecer el límite en nulo

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

y llamar a esa función

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

si desea establecer el límite, puede pasar como argumento

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

Como se aconsejó anteriormente , nada cambió. Sin embargo, tenga cuidado, demasiados parámetros (especialmente los opcionales) son un fuerte indicador del olor del código.

Quizás su función está haciendo demasiado:

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

Algunos parámetros se podrían agrupar de forma lógica:

$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 último recurso, siempre puede introducir un objeto de parámetro ad-hoc :

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

(que es solo una versión glorificada de la técnica de matriz de parámetros menos formal )

A veces, la misma razón para hacer que un parámetro sea opcional es incorrecta. En este ejemplo, ¿ $pagerealmente se pretende que sea opcional? ¿Guardar un par de personajes realmente marca la diferencia?

// 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 */);
Semilla aleatoria
fuente
0

Este fragmento:

    function getData ($ nombre, $ opciones) {
       $ predeterminado = matriz (
            'límite' => 50,
            'página' => 2,
        );
        $ args = array_merge ($ predeterminado, $ opciones);
        print_r ($ argumentos);
    }

    getData ('foo', array ());
    getData ('foo', array ('límite' => 2));
    getData ('foo', array ('límite' => 10, 'página' => 10));

La respuesta es :

     Formación
    (
        [límite] => 50
        [página] => 2
    )
    Formación
    (
        [límite] => 2
        [página] => 2
    )
    Formación
    (
        [límite] => 10
        [página] => 10
    )

nadie0day
fuente
2
Agradable. Pero una pequeña explicación sería útil.
showdev
Buena respuesta, pero si desea omitir el parámetro opcional, hágalo de esta manera: function getData ($ name, $ args = array ()) {$ defaults = array ('limit': => 50, 'page' => 2) ; $ args = array_merge ($ valores predeterminados, $ args); } Ahora es posible llamar a esta función solo con el primer parámetro como este: getData ('foo');
EchoSin
0

Esto es lo que haría:

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

?>

Espero que esto ayude a alguien

Michael Eugene Yuen
fuente
0

Esta es una pregunta antigua con una serie de respuestas técnicamente competentes, pero clama por uno de los patrones de diseño modernos en PHP: Programación Orientada a Objetos. En lugar de inyectar una colección de tipos de datos escalares primitivos, considere usar un "objeto inyectado" que contenga todos los datos necesarios para la función. http://php.net/manual/en/language.types.intro.php

El objeto inyectado puede tener rutinas de validación de propiedades, etc. Si la instanciación e inyección de datos en el objeto inyectado no puede pasar toda la validación, el código puede lanzar una excepción inmediatamente y la aplicación puede evitar el incómodo proceso de tratar con datos potencialmente incompletos.

Podemos teclear el objeto inyectado para detectar errores antes de la implementación. Algunas de las ideas se resumen en este artículo de hace unos años.

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

Ray Paseur
fuente
0

Tuve que hacer una fábrica con parámetros opcionales, mi solución fue usar el operador de fusión nula:

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

Uso:

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

No es la cosa más bonita, pero podría ser un buen patrón para usar en Factories para pruebas.

Lucas Bustamante
fuente
-1

Prueba esto.

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

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

No puede omitir el parámetro medio en su llamada de función. Pero, puedes solucionar esto:

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

Función:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}
Ronak Patel
fuente
No estoy seguro de por qué tiene votos negativos, además de que $ c también necesita un valor predeterminado (no puede tener ningún argumento requerido después de un argumento opcional).
Frank Forte
-2

Como señaló @IbrahimLawal. Es una buena práctica simplemente establecerlos en nullvalores. Simplemente verifique si el valor pasado es nullen el que usa sus valores predeterminados definidos.

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

Espero que esto ayude.

asp.patrickg
fuente
Simplemente duplicó la respuesta. Más bien podría haber votado a favor o comentado al respecto.
Ibrahim Lawal
-6
getData('some name');

simplemente no los pase y se aceptará el valor predeterminado

Shal
fuente