Модификация аргументов функций

Начнем с того, что сформулируем такое правило: аргументы функций нельзя модифицировать. Это путает того, кто читает Ваш код.

Вот, например, рассмотрим следующий кусок кода:

<?
function fn($val, $qty, $year) {
	if ($val > 70) $val -= 2;
	...
?>

Как видим, тут кто-то взял и изменил значение аргумента функции (наверно, я :) ). Причем заметим, что в PHP без явного указания аргументы всегда передаются по значению, а не по ссылке. Если по правилу, то мы должны были сделать вот так:

<?
function fn($val, $qty, $year) {
	$res = $val;
	if ($val > 70) $res -= 2;
	...
?>

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

<?
    void some_method($foo) {
        $foo.modifySomeData();  // тут все нормально
        $foo = $someObj;        // а это неправильно
        ...
?>

А в чем отличие между передачей параметра по значению и передачей параметра по ссылке? Когда мы передаем параметр в функцию по значению, его модификация внутри этой функции не приводит к его модификации снаружи, т.е. в том коде, откуда была вызвана функция, внутри которой он модифицируется. А если мы передали параметр по ссылке, мы на самом деле передали не его значение, а его адрес, по которому функция может делать с аргументом что угодно. При этом если внутри функции он будет изменен, это «почувствует» и функция, которая вызвала первую функцию.

  1. Создайте дополнительную переменную для аргумента функции, который модифицируется и присвойте ей значение аргумента;
  2. Замените все ссылки на этот аргумент новой переменной в коде;
  3. Протестируйте работу программы.

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

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

<?
    function fn(&$val, $qty, $year) {
        if ($val > 70) $val -= 2;
        if ($qty > 120) $val -= 1;
        if ($year >) $val -= 4;
    }
?>

Сделаем ее правильной:

<?
    function fn(&$val, $qty, $year) {
	$res = $val;
        if ($val > 70) $res -= 2;
        if ($qty > 120) $res -= 1;
        if ($year >) $res -= 4;
        return $res;
    }
?>

Вот и еще один небольшой приемчик в нашу копилку рефакторинг-приемов :)





Читайте также:



2 Ответов на “Модификация аргументов функций”

  1. asdf

    А как вы предлагаете быть в том случае, если требуется функция, которая не возвращает значение, а изменяет указанную переменную?
    К примеру: fn($val, 200, 2)?

  2. Александр

    У автора есть своё мнение. ИМХО, по собственному опыту, бывает удобнее, передав значение по адресу, его же и изменять в функции.


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map