- Все нюансы работы с функциями в PHP. Часть 2
- Функции, зависящие от условий
- Вложенные функции
- Область видимости переменных
- Обращение к глобальным переменным из локальной области видимости
- Передача аргументов по ссылке
- Статические переменные
- Возврат значений
- Рекурсивная функция
- Строгая типизация в PHP (уточнение типа)
- Использование аргументов переменной длины
- Заключение
Все нюансы работы с функциями в PHP. Часть 2
Заметка: активирована адаптивная версия сайта, которая автоматически подстраивается под небольшой размер Вашего браузера и скрывает некоторые детали сайта для удобства чтения. Приятного просмотра!
Здравствуйте уважаемые читатели блога Site on! В предыдущей статье мы узнали что есть функция в PHP, научились создавать собственные функции, передавать в них аргументы и вызывать их для выполнения. Продолжая тему функций в PHP необходимо подчеркнуть следующие вещи:
- Внутри функции можно использовать любой PHP код (циклы, условия, любые операции), включая другие функции (как встроенные, так и собственные);
- Имя функции должно начинаться с латинской буквы, либо знака подчёркивания, далее может идти любое количество латинских букв, цифр или знаков подчёркивания;
- Все функции имеют глобальную область видимости, это значит, что любая функция может быть вызвана в любом месте, даже если эта функция определена внутри другой;
- PHP не поддерживает перегрузку функций, также отсутствует возможность переопределить (изменить, дополнить) или удалить созданную функцию;
- Функции не обязаны быть определены до их использования. То есть если вы сначала вызовите функцию, а только потом – ниже по коду её опишите, то это не повлияет на работоспособность и не вызовет ошибок.
Функции, зависящие от условий
Мы можем создавать (определять, описывать) функцию, в зависимости от условия. Например:
//вызвали функцию sayHi, её можно вызывать в любом месте /*здесь нельзя вызвать функцию sayGoodbye, так как мы ещё не проверили условие и не зашли внутрь конструкции if*/ if($apply)< function sayGoodbye()< echo 'Всем пока!
'; > > /*вот теперь можем вызвать sayGoodbye*/ sayGoodbye(); function sayHi()< echo 'Всем привет!
'; >
И взгляните на этот пример:
/*вызвали функцию sayHi, её можно вызывать в любом месте*/ /*а вот что будет, если вызвать sayGoodbye здесь*/ sayGoodbye(); if($apply)< function sayGoodbye()< echo 'Всем пока!
'; > > function sayHi()< echo 'Всем привет!
'; >
Всё понятно из названия ошибки, разве что стоит пояснить следующую вещь: интерпретатор PHP при первом (быстром) обходе не видит что функция sayGoodbye вообще хоть где-то описана, он увидит это только когда код начнёт выполняться и только если условие будет true (читайте про типы переменных).
На самом деле, сколько я работаю, ни разу нигде такого не встречал, но иметь в виду нужно все возможности языка.
Вложенные функции
Вложенная функция – это функция, объявленная внутри другой функции. Пример:
/*Здесь нельзя вызвать sayGoodbye, так как она появится только после вызова функции sayHi*/ sayHi(); /*вызвали функцию sayHi, её можно вызывать в любом месте*/ /*Теперь можем вызывать sayGoodbye*/ sayGoodbye(); function sayHi()< echo 'Всем привет!
'; function sayGoodbye()< echo 'Всем пока!
'; > >
Опять-таки, при первом обходе интерпретатор PHP помечает себе, что он нашёл описание функции sayHi, но не заходит внутрь её тела, он видит только название, а раз интерпретатор не заходит внутрь тела sayHi, то он понятия не имеет, что внутри мы определяем ещё одну функцию – sayGoodbye.
Далее код начинает исполняться, мы вызываем sayHi, интерпретатору PHP приходиться зайти в тело функции sayHi, чтобы выполнить её и там он случайно находит описание ещё одной функции — sayGoodbye, после чего и sayGoodbye можно вызывать в любом месте, сколько угодно раз.
Но стоит обратить внимание на очень тонкий момент в ситуации выше: функция sayHi становится одноразовой, потому что если мы ещё раз её вызовем, то PHP опять наткнётся на определение функции sayGoodbye, а в PHP так делать нельзя – нельзя переопределять функции. Об этом и о том, как с этим бороться я писал в предыдущей статье.
В PHP описанные выше приёмы применяются очень редко, чаще их можно увидеть, например, в JavaScript.
Область видимости переменных
В PHP ровно две области видимости: глобальная и локальная. В каждом языке программирования области видимости устроены по-разному. Например, в C++ даже в циклах своя (локальная) область видимости. В PHP, кстати, циклы – это глобальная область видимости. Но сегодня мы говорим о функциях.
У функций в PHP своя, внутренняя область видимости (локальная), то есть все переменные внутри функции видны только внутри этой самой функции.
Итак, ещё раз: все, что вне функций – это глобальная область видимости, все, что внутри функций – локальная область видимости. Пример:
'; $name = 'Рудь Сергей'; > $name = 'Андрей'; sayHi($name); echo $name; // ?
Уважаемые знатоки, внимание, вопрос! Что выведет последняя инструкция echo $name; ?
Как вы сами видели, у нас было 2 переменных $name, одна внутри функции (локальная область видимости), другая просто в коде (глобальная область видимости), последнее присвоение в переменную $name было $name = ‘Рудь Сергей’; Но так как это было внутри функции, то там оно и осталось. В глобальной же области видимости последним присвоением было $name = ‘Андрей’; что мы собственно и видим в результате.
То есть две одинаковые переменные, но в разных областях видимости никак не пересекаются и не влияют друг на друга.
Давайте я проиллюстрирую области видимости на рисунке:
При первом обходе интерпретатор бегло просматривает глобальную область видимости, запоминает какие есть переменные и функции, но не выполняет код.
Обращение к глобальным переменным из локальной области видимости
Но что если нам всё-таки нужно из функции обратиться к той самой переменной $name из глобальной области видимости, да не просто обратиться, а изменить её? Для этого есть 3 основных варианта. Первый из них использование ключевого слова global:
'; global $name; /*начиная с этого момента мы имеем ввиду глобальную переменную $name*/ $name = 'Рудь Сергей'; > $name = 'Андрей'; sayHi($name); echo $name; // ?
Но у этого способа есть минус, с тех пор как мы обратились к глобальной переменной $name мы потеряли (переписали) локальную переменную $name.
Второй способ заключается в том, чтобы использовать суперглобальный массив PHP. В этот массив PHP сам, автоматически помещает каждую переменную, которую мы создали в глобальной области видимости. Пример:
$name = 'Андрей'; //Тоже самое что и $GLOBALS['name'] = 'Андрей';
'; $GLOBALS['name'] = 'Рудь Сергей'; > $name = 'Андрей'; sayHi($name); echo $name; // ?
Результат тот же, что и при использовании ключевого слова global:
Только в этот раз мы не переписали локальную переменную, то есть переменная $name внутри функции осталась прежней и равна «Андрей», а не «Рудь Сергей».
Передача аргументов по ссылке
Третий способ – это передача адреса (ссылки) переменной, а не её значения. Ссылки в PHP не очень удались, в отличие от других языков программирования. Тем не менее, я расскажу вам единственный правильный вариант передачи аргумента по ссылке в функцию, который нормально поддерживается в PHP 5.3 и выше. Есть и другие способы работы со ссылками, но они работали в PHP 5.2 и ниже, в итоге сами разработчики PHP решили от них отказаться, поэтому не будем о них.
Так вот, ПРАВИЛЬНАЯ передача аргумента по ссылке в PHP 5.3 и выше осуществляется следующим образом:
Мы в самом описании функции добавили значок амперсанд (&) – этот значок означает, что мы принимаем не значение переменной, а ссылку (адрес) на это значение в памяти. Ссылки в PHP позволяют создать две переменные, указывающие на одно и то же значение. Это означает, что при изменении одной из этих переменных, меняются обе, так как в памяти они обращаются к одному и тому же значению.
&$name)< //принимаем не значение, а ссылку на значение echo 'Привет, '.$name.'!
'; $name = 'Рудь Сергей'; > $name = 'Андрей'; sayHi($name); echo $name; // ?
Статические переменные
Представьте себе следующую ситуацию: нам нужно посчитать сколько раз мы всего поздоровались. Вот что мы пытаемся сделать:
// счётчик echo 'Привет, '.$name.'!
'; $c++; // увеличиваем счётчик на 1 echo 'Всего поздоровались ' . $c . ' раз.
'; > sayHi('Рудь Сергей'); sayHi('Андрей'); sayHi('Дмитрий');
Переменная $c не запоминает своего значения, она каждый раз создаётся заново. Нам нужно сделать так, чтобы наша локальная переменная $c запоминала своё значение после выполнения функции, для этого используют ключевое слово static:
static $c = 0; // счётчик, сделали статическим echo 'Привет, '.$name.'!
'; $c++; // увеличиваем счётчик на 1 echo 'Всего поздоровались ' . $c . ' раз.
'; > sayHi('Рудь Сергей'); sayHi('Андрей'); sayHi('Дмитрий');
Возврат значений
В функциях есть такая удобная вещь, как возврат значений. Это когда функция вместо того, чтобы вывести что-нибудь на экран, помещает всё в переменную и отдаёт эту переменную нам. А мы уже дальше решаем, что с ней делать. Для примера возьмём эту функцию, она возводит число в квадрат:
Сделаем так, чтобы вместо вывода на экран она возвращала результат выполнения. Для этого используется ключевое слово return:
return $result; > getSquare(5);
Теперь мы можем использовать это различными способами:
return $result; > echo getSquare(5); //выводит результат echo '
'; $num = getSquare(5); // присвоили результат в переменную echo $num; // вывели переменную на экран
Обращаю ваше внимание, что ключевое слово return не просто возвращает значение, а полностью прерывает работу функции, то есть весь код, который находится ниже ключевого слова return никогда не исполниться. Другими словами, return для функций вдобавок работает как break для циклов:
return $result; echo 'До меня PHP никогда не дойдёт :('; > echo getSquare(5); //выводит результат echo '
'; $num = getSquare(5); // присвоили результат в переменную echo $num; // вывели переменную на экран
То есть return – это ещё и выход из функции. Его можно использовать и без возвращаемого значения, только ради выхода.
Рекурсивная функция
Рекурсивная функция – это функция, которая вызывает сама себя. Рекурсия используется не часто и считается ресурсоёмкой (медленной) операцией. Но бывает, что использование рекурсии самый очевидный и простой вариант. Пример:
'; if($number < 20)< // чтобы рекурсия не стала бесконечной countPlease(++$number); // функция countPlease вызвала сама себя > > countPlease(1);
Если вы знаете, как обойтись без рекурсии, то лучше так и сделать.
Строгая типизация в PHP (уточнение типа)
В PHP сделаны мелкие шаги к строгой типизации, благодаря этому мы можем заранее указать, какой тип должна принимать функция (это называется type-hint):
array $numbers)< // какой-то код > countPlease(1);
Catchable fatal error: Argument 1 passed to countPlease() must be an array, integer given, called in /home/index.php on line 7 and defined in /home/index.php on line 3
Ошибка нам говорит, что функция ожидает принять массив, а вместо этого мы ей передаём число. К сожалению, пока что мы можем уточнять тип только для массивов (array), а с PHP 5.4 ещё добавился такой вариант как callable:
callable $v) < $v(); >countPlease(«getEcho»); function getEcho()
Callable проверяет, может ли переданное значение быть вызвано в качестве функции. Callable может быть как именем функции, заданным строковой переменной, так и объектом и именем вызываемого метода. Но про объекты и методы мы поговорим позже (это раздел объектно-ориентированного программирования), а с функциями вы уже знакомы. Результат работы я вам показать не могу, так как у меня сейчас стоит PHP 5.3, но он был бы:
Использование аргументов переменной длины
И напоследок ещё один очень редко используемый нюанс. Представьте ситуацию, мы передаём в функцию аргументы, хотя в функции мы их не описали, например:
$age = 22; getEcho('Рудь Сергей', $age);
Как видите, ошибок нет, но и наши переданные аргументы нигде не используются. Но это не значит, что они пропали – они всё равно передались в функцию и мы можем их использовать, для этого существуют встроенные функции PHP:
func_num_args() — Возвращает количество аргументов, переданных функции
func_get_arg(порядковый номер) — Возвращает элемент из списка аргументов
func_get_args() — Возвращает массив, содержащий аргументы функции
'; echo func_get_arg(0); > $age = 22; getEcho('Рудь Сергей', $age);
Заключение
Сегодняшняя статья является заключительной по теме функций в PHP. Теперь вы можете быть уверены в полноте своих знаний касательно этой темы и можете смело использовать функции для своих нужд.
Если у кого-то есть желание набить руку, но нет идей как это сделать – лучшим способом будет написание уже готовых (встроенных) функций PHP, например, можно написать собственную функцию count() или любую другую.
Благодарю всех за внимание и до новых встреч! Если что-то не понятно, смело задавайте ваши вопросы в комментариях!