назвал PHP необязательными аргументами? - PullRequest
20 голосов
/ 27 августа 2009

Возможно ли в PHP 4/5 указывать именованный необязательный параметр при вызове, пропуская те, которые вы не хотите указывать (как в python)?

Что-то вроде:

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


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

Спасибо

Ответы [ 17 ]

21 голосов
/ 27 августа 2009

Нет, это невозможно: если вы хотите передать третий параметр, вы должны передать второй. И именованные параметры также невозможны.


«Решением» было бы использование только одного параметра, массива, и всегда передавать его ... Но не всегда определять все в нем.

Например:

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

И называя это так:

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

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

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

Получит вам этот вывод:

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)

Но мне не очень нравится это решение:

  • Вы потеряете phpdoc
  • Ваша IDE больше не сможет давать подсказки ... Что плохо

Так что я бы пошел с этим только в очень специфических случаях - например, для функций с большим количеством дополнительных параметров ...

6 голосов
/ 23 мая 2012

Нет, PHP не может передавать аргументы по имени.

Если у вас есть функция, которая принимает много аргументов, и у всех них есть значения по умолчанию, вы можете рассмотреть возможность принятия функции вместо массива аргументов:

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       
}

Посмотреть в действии .

3 голосов
/ 26 марта 2015

Начиная с PHP 5.4 у вас есть сокращенный синтаксис массива (необязательно указывать массивы с громоздким «массивом» и вместо этого использовать «[]»).

Вы можете имитировать именованные параметры разными способами, одним хорошим и простым способом может быть:

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;
}
3 голосов
/ 27 августа 2009

Нет, это не так.

Единственный способ, которым вы можете это сделать, - использовать массивы с именованными ключами, а что нет.

2 голосов
/ 27 августа 2009

В PHP важен порядок аргументов. Вы не можете указать конкретный аргумент неуместно, но вместо этого вы можете пропустить аргументы, передав NULL, если вы не против значения в вашей функции, имеющего значение NULL.

foo("hello", NULL, "bar");
1 голос
/ 27 марта 2014

Обычно вы не можете, но я думаю, что есть много способов передать именованные аргументы в функцию PHP. Лично я передаю определение с использованием массивов и просто вызываю то, что мне нужно передать:

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();

живой пример здесь: http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff

Если мне нужно передать 10 аргументов, и 3 из них - это данные, которые мне действительно нужны, ДАЖЕ НЕ УМНЫЙ для передачи в функцию что-то вроде

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

С подходом, который я даю, вы можете установить любой из 10 аргументов в массив:

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

У меня есть запись в моем блоге, объясняющая этот процесс более подробно.

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

1 голос
/ 13 декабря 2011

Вы можете сохранить phpdoc и возможность устанавливать значения по умолчанию, передавая объект вместо массива, например,

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

Это также позволяет вам выполнять строгую проверку типов при вызове функции, если вы хотите:

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

Конечно, вы можете заплатить за это дополнительной детализацией, установив объект FooOptions. К сожалению, нет абсолютно бесплатной поездки.

1 голос
/ 30 августа 2009

Это не совсем красиво, но, как некоторые могут сказать, это помогает.

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 голосов
/ 23 мая 2012

Вы не можете сделать это способом питона. В любом случае, вы можете передать ассоциативный массив, а затем использовать записи массива по их имени:

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

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

Это не сокращает типизацию, но, по крайней мере, более наглядно, так как имена аргументов видимы и читаемы в вызове.

0 голосов
/ 23 мая 2012

Короче говоря, иногда да, используя отражение и типизированные переменные. Однако я думаю, что это, вероятно, не то, что вы после.

Лучшим решением вашей проблемы, вероятно, является передача трех аргументов, поскольку функции сами обрабатывают отсутствующий внутри вашей функции

<?php  
   function test(array $params)
   {
     //Check for nulls etc etc
     $a = $params['a'];
     $b = $params['b'];
     ...etc etc
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...