Использование аргументов по умолчанию в функции - PullRequest
157 голосов
/ 07 февраля 2012

Меня смущают значения по умолчанию для функций PHP. Скажем, у меня есть такая функция:

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

Что, если я хочу использовать аргумент по умолчанию для $ x и установить другой аргумент для $ y?

Я экспериментировал с разными способами, и я просто запутался. Например, я попробовал эти два:

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

Но оба из них не приводят к правильному аргументу по умолчанию для $ x. Я также пытался установить его по имени переменной.

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

Я полностью ожидал, что что-то подобное сработает. Но это не работает, как я ожидал. Кажется, что независимо от того, что я делаю, мне все равно придется заканчивать вводом аргументов по умолчанию, каждый раз, когда я вызываю функцию. И я, должно быть, упускаю что-то очевидное.

Ответы [ 11 ]

148 голосов
/ 07 февраля 2012

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

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

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

    code here!

}

Таким образом, вы можете сделать вызов наподобие foo('blah', null, 'non-default y value'); и заставить его работать так, как вы хотите, гдевторой параметр $x по-прежнему получает значение по умолчанию.

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

Как указано в других ответах,

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

Если у меня есть метод, который может принимать переменное число параметров, ипараметры различных типов, я часто объявляю функцию, подобную ответу, показанному Райаном П.

Вот еще один пример (это не отвечает на ваш вопрос, но, надеюсь, информативно:

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!");
    }
}
35 голосов
/ 07 февраля 2012

Необязательные аргументы работают только в конце вызова функции.Невозможно указать значение $ y в вашей функции без указания $ x.Некоторые языки поддерживают это с помощью именованных параметров (например, VB / C #), но не PHP.

Вы можете эмулировать это, если вы используете ассоциативный массив для параметров вместо аргументов - то есть

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

    ...
}

Затем вызовите функцию так:

foo(array('y' => 'my value'));
19 голосов
/ 18 ноября 2016

На самом деле это возможно:

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

Хотите ли вы сделать это, это другая история:)


ОБНОВЛЕНИЕ:

Причины, по которым следует избегатьЭто решение:

  • (возможно) уродливо
  • имеет очевидные накладные расходы.
  • как другие ответы доказывают, есть альтернативы

Но на самом деле это может быть полезно в ситуациях, когда:

  • вы не хотите / можетеНе меняйте исходную функцию.
  • Вы можете изменить функцию, но:

    • с использованием null (или эквивалентным) не является опцией (см. DiegoDD's комментарий )
    • вы не хотите идти с ассоциативным или с func_num_args()
    • ваша жизнь зависит от сохранения нескольких LOC

Что касается производительности, очень простой тест показывает, что использование Reflection API для получения параметров по умолчанию делает вызов функции 25 раз медленнее , хотя это все еще занимает менее одной микросекунды .Вы должны знать, если вы можете жить с этим.

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

10 голосов
/ 19 октября 2015
function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}
3 голосов
/ 07 февраля 2012

Единственный способ сделать это - пропустить параметр. Единственный способ опустить параметр - это переставить список параметров так, чтобы тот, который вы хотите опустить, находится после параметров, которые вы HAVE установите. Например:

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

Тогда вы можете позвонить Фу, как:

foo("blah", "test");

Это приведет к:

$blah = "blah";
$y = "test";
$x = "some value";
2 голосов
/ 10 января 2018

У меня недавно была эта проблема, и я нашел этот вопрос и ответы.Хотя вышеуказанные вопросы работают, проблема в том, что они не показывают значения по умолчанию для IDE, которые его поддерживают (например, PHPStorm).

enter image description here

, есливы используете null, вы не будете знать, какое значение будет, если оставить его пустым.

Решение, которое я предпочитаю, - это добавить значение по умолчанию в определение функции:

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

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

2 голосов
/ 07 февраля 2012

Вы не можете сделать это напрямую, но небольшая путаница кода позволяет эмулировать.

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

  // code
}
1 голос
/ 26 сентября 2018
<?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 голосов
/ 14 февраля 2019

Передайте массив функции вместо отдельных параметров и используйте оператор объединения нулей (PHP 7+).

Ниже я передаю массив с 2 элементами. Внутри функции я проверяю, установлено ли значение для item1, если не назначено хранилище по умолчанию.

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

    function function_name ($args) {
        isset($args['item1']) ? $args['item1'] : 'default value';
    }
0 голосов
/ 10 февраля 2015

Вы также можете проверить, есть ли у вас пустая строка в качестве аргумента, чтобы вы могли вызвать как:

foo('blah', "", 'non-default y value', null);

ниже функции:

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

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

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

    code here!

}

Неважно, если вы заполните null или "", вы все равно получите тот же результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...