Использование аргументов по умолчанию в функции


Я запутался в значениях по умолчанию для функций 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");   

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

10 130

10 ответов:

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

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 по-прежнему получает значение по умолчанию.

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

как указано в другом отвечает,

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

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

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

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!");
    }
}

необязательные аргументы работают только в конце вызова функции. Невозможно указать значение для $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'));

это действительно возможно:

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

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


обновление:

причин, чтобы избежать этого решения являются:

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

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

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

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

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

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

function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}

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

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

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

foo("blah", "test");

в результате:

$blah = "blah";
$y = "test";
$x = "some value";

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

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

  // code
}

недавно у меня была эта проблема, и я нашел этот вопрос и ответы. Хотя вышеуказанные вопросы работают, проблема в том, что они не показывают значения по умолчанию для 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;
    ...

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

Это случай, когда объект лучше - потому что вы можете настроить свой объект на удержание x и y , настроить значения по умолчанию и т. д.

подход с массивом близок к созданию объекта (на самом деле, объект-это куча параметров и функций, которые будут работать над объектом, а функция, принимающая массив, будет работать над некоторыми параметрами группы ov )

Cerainly вы всегда можете сделать некоторые трюки, чтобы установить null или что-то вроде этого по умолчанию

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

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 или "", вы все равно получите тот же результат.

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

?>