2009-08-27 18 views
20

¿Es posible en PHP 4/5 especificar un parámetro opcional con nombre al llamar, omitiendo los que no desea especificar (como en python)?llamados argumentos opcionales PHP?

Algo así como:

function foo($a,$b='', $c='') { 
    // whatever 
} 


foo("hello", $c="bar"); // we want $b as the default, but specify $c 

Gracias

+2

En realidad, en su ejemplo de código, el '$ c = "bar"' 'es asignar a un bar' sean' $ c' en * el alcance de llamadas * (no en la función llamada 'foo') y luego pasando el valor asignado a 'foo()' como el segundo parámetro, que se recibirá como la variable local '$ b'. – Petruza

Respuesta

21

No, no es posible: si desea pasar el tercer parámetro, debe pasar el segundo. Y los parámetros nombrados tampoco son posibles.


Una "solución" sería usar solo un parámetro, una matriz, y siempre pasarlo ... Pero no siempre define todo en ella.

Por ejemplo:

function foo($params) { 
    var_dump($params); 
} 

Y llamando de esta manera:

foo(array(
    'a' => 'hello', 
)); 

foo(array(
    'a' => 'hello', 
    'c' => 'glop', 
)); 

foo(array(
    'a' => 'hello', 
    'test' => 'another one', 
)); 

Se puede obtener este resultado:

array 
    'a' => string 'hello' (length=5) 

array 
    'a' => string 'hello' (length=5) 
    'c' => string 'glop' (length=4) 

array 
    'a' => string 'hello' (length=5) 
    'test' => string 'another one' (length=11) 

pero no me gusta mucho esta solución:

  • Usted perderá el phpdoc
  • El IDE no va a ser capaz de proporcionar cualquier indicio más ... lo cual es malo

Así que me gustaría ir con esto sólo en casos muy específicos - para funciones con muchos parámetros opcionales, por ejemplo ...

+0

Lo siento por el OT, pero ¿conoces algún editor que proporcione sugerencias de código para PHP? cualquiera para MacOS? ¡Gracias! – Petruza

+0

sugerencias de código? Diría que todos los IDE do (netbeans, Eclipse PDT, PHPStorm, ...); ninguna idea sobre Mac; pero esos podrían funcionar en Mac –

+0

@ Petruza en caso de que aún no lo hayas encontrado, prueba Coda para MacOS. Hace un buen trabajo al insinuar PHP. – EFC

2

Con PHP, el orden de los argumentos es lo que importa. No puede especificar un argumento particular fuera de lugar, pero en su lugar, puede omitir argumentos pasando un NULO, siempre y cuando no le importe que el valor en su función tenga un valor NULO.

foo("hello", NULL, "bar"); 
+1

NULL no es el valor predeterminado, no siempre, y no en este caso: aquí, el valor predeterminado sería una cadena vacía; y no, NULL y una cadena vacía no son "lo mismo": ver operadores === y! ==, por ejemplo ... –

+0

Oh, no me había dado cuenta de que era NULL en lugar de estar vacío, ya que siempre estoy usando '' como predeterminado y luego verificando si (! $ value) – davethegr8

3

No, no lo es.

La única forma en que puede hacer algo de eso es mediante el uso de matrices con claves con nombre y lo que no.

+1

El CakePHP -al menos- usa este patrón extensamente –

1

No es exactamente bonito, pero hace el truco, algunos podrían decir.

class NamedArguments { 

    static function init($args) { 
     $assoc = reset($args); 
     if (is_array($assoc)) { 
      $diff = array_diff(array_keys($assoc), array_keys($args)); 
      if (empty($diff)) return $assoc; 
      trigger_error('Invalid parameters: '.join(',',$diff), E_USER_ERROR); 
     } 
     return array(); 
    } 

} 

class Test { 

    public static function foobar($required, $optional1 = '', $optional2 = '') { 
     extract(NamedArguments::init(get_defined_vars())); 
     printf("required: %s, optional1: %s, optional2: %s\n", $required, $optional1, $optional2); 
    } 

} 

Test::foobar("required", "optional1", "optional2"); 
Test::foobar(array(
    'required' => 'required', 
    'optional1' => 'optional1', 
    'optional2' => 'optional2' 
    )); 
0

Esto es lo que he estado usando. Una definición de función toma un argumento de matriz opcional que especifica los argumentos con nombre opcionales:

function func($arg, $options = Array()) { 
    $defaults = Array('foo' => 1.0, 
        'bar' => FALSE); 
    $options = array_merge($default, $options); 

    // Normal function body here. Use $options['foo'] and 
    // $options['bar'] to fetch named parameter values. 
    ... 
} 

Normalmente se puede llamar sin ningún tipo de argumentos con nombre:

func("xyzzy") 

Para especificar un argumento con nombre opcional, pasarlo en el opcional matriz:

func("xyzzy", Array('foo' => 5.7)) 
1

puede mantener el phpdoc y la capacidad de establecer los valores predeterminados mediante el paso de un objeto en lugar de una matriz, por ejemplo,

class FooOptions { 
    $opt1 = 'x'; 
    $opt2 = 'y'; 
    /* etc */ 
}; 

Eso también le permite hacer estricta comprobación de tipos en su llamada a la función, si se quiere:

function foo (FooOptions $opts) { 
    ... 
} 

Por supuesto, es posible que pagar por ello con el nivel de detalle adicional objeto la creación de los FooOptions. No hay un paseo totalmente libre, desafortunadamente.

6

No, PHP no puede pasar argumentos por nombre.

Si usted tiene una función que toma un montón de argumentos y todos ellos tienen valores por defecto se puede considerar la posibilidad de aceptar la función de una serie de argumentos en su lugar:

function test (array $args) { 
    $defaults = array('a' => '', 'b' => '', 'c' => ''); 
    $args = array_merge($defaults, array_intersect_key($args, $defaults)); 

    list($a, $b, $c) = array_values($args); 
    // an alternative to list(): extract($args); 

    // you can now use $a, $b, $c  
} 

See it in action.

0

No realmente. Hay algunas alternativas que podrías usar.

test(null,null,"hello") 

O pasar un array:

test(array('c' => "hello")); 

Entonces, la función podría ser:

function test($array) { 
    $c = isset($array[c]) ? $array[c] : ''; 
} 

O agregar una función en el medio, pero yo no recomendaría esto:

function ctest($c) { test('','',$c); } 
0

Probar function test ($a="",$b="",&$c=""){}

Poner & antes de la $c

0

No lo creo ... Si necesita llamar, por ejemplo, la función substr, que tiene 3 params, y quieren establecer la longitud $ sin establezca $ start, se lo forzará a hacerlo.

substr($str,0,10); 

una buena manera de anular este es utilizar siempre matrices para los parámetros

0

Respuesta simple. No, no puedes.
Puede tratar de evitarlo pasando un objeto/matriz o utilizando algunos otros patrones de inyección de Dependencia.

Además, trate de utilizar los nulos en lugar de cadenas vacías, ya que es más definido para la prueba de su existencia utilizando is_null()

por ejemplo:

function test ($a=null,$b=null,$c=null){ 
if (is_null($a) { 
    //do something about $a 
} 
if (is_null($b) { 
    //do something about $b 
} 
if (is_null($c) { 
    //do something about $c 
} 
} 

llamar a esto:

test(null,null,"Hello"); 
0

En muy corto, a veces sí, mediante el uso de variables de reflexión y tipadas. Sin embargo, creo que probablemente esto no sea lo que buscas.

Una mejor solución a su problema es probablemente acontecerá en los 3 argumentos como funciones manejan la que se perdió dentro de su función manualmente

<?php 
    function test(array $params) 
    { 
    //Check for nulls etc etc 
    $a = $params['a']; 
    $b = $params['b']; 
    ...etc etc 
    } 
0

Usted no puede hacerlo de la manera pitón. Anway, que podría pasar un arreglo asociativo y de utilizar las entradas de matriz por su nombre:

function test ($args=array('a'=>'','b'=>'','c'=>'')) 
{ 
    // do something 
} 

test(array('c'=>'Hello')); 

Esto no reduce la tipificación, pero al menos es más descriptivo, que tiene los nombres de los argumentos de visible y legible en el llamada.

+1

Ermmm, ¡eso no es una sintaxis php válida! –

+0

Disculpe, se debe arreglar ahora. –

1

Normalmente no se puede, pero creo que hay muchas maneras de pasar argumentos con nombre a una función de PHP. Personalmente relé en la definición utilizando matrices y a llamar lo que tengo que pasar:

class Test{ 
    public $a = false; 
    private $b = false; 
    public $c = false; 
    public $d = false; 
    public $e = false; 
    public function _factory(){ 
     $args = func_get_args(); 
     $args = $args[0]; 
     $this->a = array_key_exists("a",$args) ? $args["a"] : 0; 
     $this->b = array_key_exists("b",$args) ? $args["b"] : 0; 
     $this->c = array_key_exists("c",$args) ? $args["c"] : 0; 
     $this->d = array_key_exists("d",$args) ? $args["d"] : 0; 
     $this->e = array_key_exists("e",$args) ? $args["e"] : 0; 
    } 
    public function show(){ 
     var_dump($this); 
    } 
} 


$test = new Test(); 
$args["c"]=999; 
$test->_factory($args); 
$test->show(); 

ejemplo vivo aquí: http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff

Si tengo que pasar 10 argumentos, y 3 de ellos son los datos que realmente necesita, no es ni siquiera SMART para pasar a la función de algo así como

return myfunction(false,false,10,false,false,"date",false,false,false,"desc"); 

con el enfoque que estoy dando, puede configurar cualquiera de los 10 argumentos en una matriz:

$arr['count']=10; 
$arr['type']="date"; 
$arr['order']="desc"; 
return myfunction($arr); 

Tengo una publicación en mi blog explicando este proceso en más detalles.

http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php

2

A partir de PHP 5.4 que tienen sintaxis de matrices de forma abreviada (no nessecary para especificar matrices con "matriz" engorroso y en lugar de utilizar "[]").

Puede imitan parámetros con nombre en muchas maneras, una buena y sencilla podría ser:

bar('one', ['a1' => 'two', 'bar' => 'three', 'foo' => 'four']); 
// output: twothreefour 

function bar ($a1, $kwargs = ['bar' => null, 'foo' => null]) { 
    extract($kwargs); 
    echo $a1; 
    echo $bar; 
    echo $foo; 
} 
+0

Pero no '$ bar' no estaría indefinido si llamara a' bar ('one', ['x' => 'blah']); '? Incluso en este escenario, 'extract()' parece peligroso e innecesario ... – binki

0

Aquí hay un trabajo en torno a:

function set_param_defaults($params) { 
    foreach($params['default_values'] as $arg_name => $arg_value) { 
    if (!isset($params[$arg_name])) { 
     $params[$arg_name] = $arg_value; 
    } 
    } 

    return $params; 
} 

function foo($z, $x = null, $y = null) { 
    $default_values = ['x' => 'default value for x', 'y' => 'default value for y']; 
    $params = set_param_defaults(get_defined_vars()); 

    print "$z\n"; 
    print $params['x'] . "\n"; 
    print $params['y'] . "\n"; 
} 

foo('set z value', null, 'set y value'); 
print "\n"; 
foo('set z value', 'set x value'); 

Alternativa: Personalmente iría con este método.

function foo($z, $x_y) { 
    $x_y += ['x' => 'default value for x', 'y' => 'default value for y']; 

    print "$z\n"; 
    print $x_y['x'] . "\n"; 
    print $x_y['y'] . "\n"; 
} 

foo('set z value', ['y' => 'set y value']); 
print "\n"; 
foo('set z value', ['x' => 'set x value']); 

Impresiones para ambos ejemplos.

primera llamada:

  • valor fijado z
  • valor predeterminado para x
  • conjunto Y valor

segunda llamada:

  • conjunto de valores z
  • se t valor x
  • valor predeterminado para y
0

Sólo tiene que utilizar el patrón de matriz asociativa utiliza Drupal. Para los argumentos predeterminados opcionales, simplemente acepte un argumento $options que es una matriz asociativa. A continuación, utilice el operador de matriz + para establecer las claves que faltan en la matriz.

function foo ($a_required_parameter, $options = array()) { 
    $options += array(
     'b' => '', 
     'c' => '', 
    ); 
    // whatever 
} 

foo('a', array('c' => 'c’s value')); // No need to pass b when specifying c. 
Cuestiones relacionadas