Тестирование необязательных аргументов в PHP - PullRequest
17 голосов
/ 19 декабря 2011

У меня есть несколько методов «установки» для разных классов, и для удобства я добавил необязательный параметр $previous, который принимает аргумент по ссылке и заполняет его существующим значением, прежде чем заменить его новым. Например:

public function set_value($key, $value, &$previous = null)
{
    $previous = $this->get_value($key);
    $this->_values[$key] = $value;
    return $this;
}

Это отлично работает; однако в некоторых случаях соответствующий метод «получения» является немного интенсивным процессом, и запуск его безоговорочно является пустой тратой. Я решил, что смогу проверить:

if(null !== $previous)
{
    $previous = $this->get_value($key);
}

Однако это не работает, так как часто переменная, передаваемая в качестве аргумента для $previous, ранее не определялась в своей области видимости, и в любом случае по умолчанию имеет значение null. Единственное решение, которое я взломал:

public function set_value($key, $value, &$previous = null)
{
    $args = func_get_args();
    if(isset($args[2])
    {
        $previous = $this->get_value($key);
    }
    $this->_values[$key] = $value;
    return $this;
}

Или в одну строку:

if(array_key_exists(2, func_get_args()))
{
    // ...
}

Мне не нравится, когда тело метода полагается на индексы аргументов (, когда кажется, что это не нужно) ) Есть ли более чистый способ достичь того, чего я добиваюсь здесь?


Я пробовал:

if(isset($previous)){}

if(!empty($previous)){}

if(null !== $previous){}

Ни одна из работ.

Возможные решения на данный момент:

if(func_num_args() == $num_params){}

if(array_key_exists($param_index, func_get_args())){}

// 5.4
if(isset(func_get_args()[$param_index])){}

// 5.4
if(func_num_args() == (new \ReflectionMethod(__CLASS__, __FUNCTION__))
    ->getNumberOfParameters()){}

@ DaveRandom - Итак, что-то в области:

define('_NOPARAM', '_NOPARAM' . hash('sha4096', microtime()));

function foo($bar = _NOPARAM)
{
    // ...
}

@ hoppa - Вариант использования:

$obj->set_something('some_key', $some_value, $previous) // set
    ->do_something_that_uses_some_key()
    ->set_something('some_key', $previous) // and reset
    ->do_something_that_uses_some_key()
    -> ...

Вместо:

$previous = $obj->get_something('some_key'); // get
$obj->set_something('some_key', $some_value) // set
    ->do_something_that_uses_some_key();
    ->set_something($previous) // and reset
    ->do_something_that_uses_some_key();
    -> ...

Ответы [ 2 ]

3 голосов
/ 19 декабря 2011

возможно, не так, как вы хотели решить вашу проблему (тестируя какие-то необязательные аргументы), но я бы это реализовал так:

public function set_value($key, $value)
{
    $this->_values[$key] = $value;
    return $this;
}
public function set_get_value($key, $value, &$previous)
{
    $previous = $this->get_value($key);
    $this->_values[$key] = $value;
    return $this;
}

Пример использования:

$obj->set_get_something('some_key', $some_value, $previous) // set AND get
    ->do_something_that_uses_some_key()
    ->set_something('some_key', $previous) // and reset
    ->do_something_that_uses_some_key()
    -> ...

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

У этого решения есть несколько преимуществ:

  1. имя более явное, меньше путаницы для других кодировщиков
  2. без скрытых побочных эффектов
  3. решает вашу проблему с (неопределенными) переменными, уже имеющими значение
  4. без накладных расходов при вызове func_num_args или какой-либо другой "мета" функции

РЕДАКТИРОВАТЬ: опечатка в коде.

РЕДАКТИРОВАТЬ 2: удалено значение по умолчанию для функции & $ previous set_get_value () (спасибо draevor)

2 голосов
/ 19 декабря 2011

Извлечено из комментариев / обсуждений выше:

Чтобы проверить, был ли передан аргумент, у вас есть 2 варианта - сравнить значение аргумента со значением (как вы сделали с нулем) илипроверьте количество аргументов.

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

Я думаю, что второй вариант является наиболее чистым (быстрый, читаемый и т. Д.).В качестве небольшого улучшения по сравнению с тем, что вы уже сделали с func_get_args, я бы использовал func_num_args - так вы будете проверять количество переданных аргументов, а не индексы аргументов.

...