Модификация аргументов функций
Начнем с того, что сформулируем такое правило: аргументы функций нельзя модифицировать. Это путает того, кто читает Ваш код.
Вот, например, рассмотрим следующий кусок кода:
<? 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; // а это неправильно ... ?>
А в чем отличие между передачей параметра по значению и передачей параметра по ссылке? Когда мы передаем параметр в функцию по значению, его модификация внутри этой функции не приводит к его модификации снаружи, т.е. в том коде, откуда была вызвана функция, внутри которой он модифицируется. А если мы передали параметр по ссылке, мы на самом деле передали не его значение, а его адрес, по которому функция может делать с аргументом что угодно. При этом если внутри функции он будет изменен, это «почувствует» и функция, которая вызвала первую функцию.
- Создайте дополнительную переменную для аргумента функции, который модифицируется и присвойте ей значение аргумента;
- Замените все ссылки на этот аргумент новой переменной в коде;
- Протестируйте работу программы.
При этом нужно проверить, если аргумент принимается в функции по ссылке, не используется ли модифицированный аргумент в вызвавшем нашу функцию коде. Если используется, то его модифицированное значение нужно естественно вернуть этому вызвавшему коду (с помощью 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; } ?>
Вот и еще один небольшой приемчик в нашу копилку рефакторинг-приемов
А как вы предлагаете быть в том случае, если требуется функция, которая не возвращает значение, а изменяет указанную переменную?
К примеру: fn($val, 200, 2)?
У автора есть своё мнение. ИМХО, по собственному опыту, бывает удобнее, передав значение по адресу, его же и изменять в функции.