Сайт вебмастера

Передача параметров в php-функцию

05-01-2008Время чтения ~ 2 мин.PHP 44549

PHP-функция может принимать параметры, например так:

function f1( $arg1, $arg2 )

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

function f1( $arg1, $arg2, $arg3 = '', $arg4 = '' )

То есть теперь, если при вызове функции не указывать последние два аргумента, то им будут присвоены дефолтные значения: в нашем случае - пустая строка.

Проходит еще какое-то время и мы решаем добавить в нашу функцию еще и параметры для форматирования. Например html-элементы «до» и «после», class, шаблон форматирования и т.д. Получается, что параметров у нашей функии становится довольно много и пользоваться ей уже не совсем удобно. Тем более может возникнуть ситуация, когда указать нужно не все параметры, а скажем только 5-й и 8-й.

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

function f1( $args = '' )
{
	parse_str($args, $r);
...

Пример вызова:

f1('b=555&a=777');

В результате в массиве $r окажется структура:

Array
(
    [a] => 777
    [b] => 555
)

Казалось бы, что проблема решена: мы можем не изменяя объявления функции, менять её функционал. Но есть один нюанс. Связан он с тем, что строчка параметров должна передаваться по правилам URL-строки, где необходимо заменять служебные символы (кавычки, пробелы и т.д.) на их коды. Таким образом, перед тем, как выполнить parse_str, нужно выполнить парсинг строки.

Всё это не совсем удобно, но мы видим, что в результате нам всё равно нужно получить массив параметров. Так что нам мешает сразу передавать в параметре готовый массив?

Вот пример:

	function f1($args = array())
	{
		if ( is_array($args) ) $r = $args;
			else parse_str($args, $r);

		# контроль
		echo '<pre>';
		print_r( $r );
		echo '</pre>';
	}

	# примеры вызова
	f1( array ('a' => '888') );
	f1( 'b=555&a=777' );

Обратите внимание, что функция сама проверяет тип параметра (is_array). Если это не массив, то выполняется parse_str. Получается универсальный подход.

Однако это еще не всё. Как быть в случае, если в параметрах переданы не все значения? Тут есть два подхода.

Первый - это явно прописать проверку на существование значения и если его нет, то взять дефолтное:

if ( !isset($r['a']) ) $r['a'] = '1';
if ( !isset($r['b']) ) $r['b'] = '2';

Второй способ - это задать массив дефолтных значений, который мы просто объединяем с входящим:

$default = array(
		'a' => '1',
		'b' => '2',
		'c' => '3',
	);

	$r = array_merge($default, $r);

Теперь, при вызове:

f1( array ('a' => '888', 'c' => '999') );

Получим в $r:

Array
(
    [a] => 888
    [b] => 2
    [c] => 999
)

Как видите, все довольно просто и элегантно. :)

Похожие записи
Комментарии (18) RSS
1 LitoX 2008-01-05 14:15:02

все эти кода мучают :smile:


2 FX Poster 2008-01-05 14:34:58

По-моему, если возникают такие функции в программе - пора заняться рефакторингом... Это то же самое, что делать в базе данных текстовые поля типа string (text, напринципиально) и записывать туда xml - типа офигенно расширяемо.


3 CTapbIu 2008-01-05 14:48:07

зачем xml, просто сериализированный массив ,)

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


4 FX Poster 2008-01-05 14:50:50

А нахрена тогда у функции несколько параметров было делать. :) Если есть один универсальный. :)


5 Максим 2008-01-05 15:27:12

Так оно всегда вначале кажется, что хватит пары параметров, а уже после вдруг понимаешь, что нужно еще парочка. Я приведу на примере WordPress'а. Есть функции вывода рубрик/ссылок/т.п. Если бы в них можно было бы передать параметры через массив, но не было бы ни проблемы совместимости, ни сложностей с оформлением. А сейчас же классы, элементы до/после жестко вбиты в функции. ИМХО - неудобно - первое же обновление и все заново приходится менять. Многие на этом накололись. :sad:


6 FX Poster 2008-01-05 15:33:48

Ну, если честно - по проектированию Wordpress отнюдь не идеал. ;)

А вот появление таких функций - это просто плохо с точки зрения проектирования.

Кстати, если вывод ссылок оформить ввиде обьектов/классов - получилось бы гораздо удобнее.


7 Tapac 2008-01-05 19:00:28

В целом полезно, но позабавил вот это текст:

перед тем, как выполнить parse_str, нужно выполнить парсинг строки.

Учитывая, что parse_str можно перевести как парсинг_строки )))

Просто каламбур, так сказать)


8 Артём Курапов 2008-01-05 19:03:51

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


9 Коля Дубр 2008-01-05 23:37:48

Такой подход действительно полезен и удобен для всяких "настроечных" методов. В остальных случаях - надо думать. Что проще запоминать: порядок передачи аргументов (если больше 3 - уже фигово), ключи массива (+что там по умолчанию), или несколько разных методов (хорошо, если получается ясный логичный интерфейс, хотя часто найти таковой не удается).


10 cryonyx 2008-01-06 03:39:00

Макс, а чем тебя не устраивает func_get_args() и родственные ей функции?


11 Максим 2008-01-06 09:25:46

2cryonyx: Тем, что в таких случаях нужно перебирать входящие параметры по номерам. Как определить, что переданный параметр это «элемент "до"», а не «элемент "после"»?


12 Anton 2008-01-06 10:27:04

Огромный пардон, что не очень по месту задаю вопрос - но уж очень припекло! Несколько часов мучался, искал способ, как убрать из сайдбара вордпресса какой-либо блок (скажем, dtree), на основании юзер-левела читающего. Ничего не нашёл((. Т.к. если в dtree указать, что пустые категории должны скрываться, и при этом применить disclose-secret плагин, то dtree сходит с ума, и показывает или только те папки, где нет скрываемых disclose-ом постов, или показывает сразу все, вне зависимости от уровня юзера. Так что выход один - просто убирать dtree целиком из сайдбара, если уровень пользователя меньше, скажем, второго. Но только как это сделать?((( Подозреваю, что нужно добавить в код что-то типа "иф юзер левел блаблабла...", но не кодер я((. Так что в целом типа прошу помощи, граждане посетители!!)


13 CTapbIu 2008-01-06 19:49:44
Anton if (current_user_can('level_?')) { .... }

вместо level_?:

level_0 == subscriber

level_1 == contributor

level_2-level_4 == author

level_5-level_7 == editor

level_8-level_10 == administrator

ну или

if (current_user_can('%role%')) { .... }

где %role% что нибудь из: subscriber, contributor, author, editor или administrator


14 Dmitry Yashin 2008-01-08 13:01:19
Тем более может возникнуть ситуация, когда указать нужно не все параметры, а скажем только 5-й и 8-й.

function f1( $arg1, $arg2, $arg3 = '', $arg4 = '')

Укажем четвертый, неуказывая третий:

f1('arg1', 'arg2', null, 'arg4')

Все просто и не стоит заморачиваться ;)


15 Severus 2008-03-13 11:56:23

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

<br>$application->Func1(<br> "some_arg",<br> "some_arg_2",<br> Array(<br>         здоровый массив с настройками и параметрами<br>        )<br>);<br>

16 Lektor 2008-06-23 03:01:21

Сенк за статью .. как раз то что искал ... правда ответ н свой вопрос нашел в коментах: сенкс Dmitry Yashin.


17 Vlad 2010-05-06 20:29:58
Все просто и не стоит заморачиваться ;)

null-то всё равно надо писать. а если он там не один?

в общем, если бы всё было так просто, Максим не стал бы заморачиваться ;)


18 Жутик 2011-04-20 12:21:04

В узко-специализированных местах выглядит вполне красиво, но как панацея от неё больше вреда, чем пользы.

Пятёрка за нестандартность мышления.

В MaxSite CMS это где-то применяется/будет применяться?