Здравствуйте уважаемые читатели блога Site on! В предыдущей статье мы узнали что есть функция в PHP, научились создавать собственные функции, передавать в них аргументы и вызывать их для выполнения. Продолжая тему функций в PHP необходимо подчеркнуть следующие вещи:
Мы можем создавать (определять, описывать) функцию, в зависимости от условия. Например:
<?php $apply = true; sayHi(); //вызвали функцию sayHi, её можно вызывать в любом месте /*здесь нельзя вызвать функцию sayGoodbye, так как мы ещё не проверили условие и не зашли внутрь конструкции if*/ if($apply){ function sayGoodbye(){ echo 'Всем пока! <br>'; } } /*вот теперь можем вызвать sayGoodbye*/ sayGoodbye(); function sayHi(){ echo 'Всем привет! <br>'; }
Результат:
И взгляните на этот пример:
<?php $apply = true; sayHi(); /*вызвали функцию sayHi, её можно вызывать в любом месте*/ /*а вот что будет, если вызвать sayGoodbye здесь*/ sayGoodbye(); if($apply){ function sayGoodbye(){ echo 'Всем пока! <br>'; } } function sayHi(){ echo 'Всем привет! <br>'; }
Результат:
Всё понятно из названия ошибки, разве что стоит пояснить следующую вещь: интерпретатор PHP при первом (быстром) обходе не видит что функция sayGoodbye вообще хоть где-то описана, он увидит это только когда код начнёт выполняться и только если условие будет true (читайте про типы переменных).
На самом деле, сколько я работаю, ни разу нигде такого не встречал, но иметь в виду нужно все возможности языка.
Вложенная функция – это функция, объявленная внутри другой функции. Пример:
<?php /*Здесь нельзя вызвать sayGoodbye, так как она появится только после вызова функции sayHi*/ sayHi(); /*вызвали функцию sayHi, её можно вызывать в любом месте*/ /*Теперь можем вызывать sayGoodbye*/ sayGoodbye(); function sayHi(){ echo 'Всем привет! <br>'; function sayGoodbye(){ echo 'Всем пока! <br>'; } }
Опять-таки, при первом обходе интерпретатор PHP помечает себе, что он нашёл описание функции sayHi, но не заходит внутрь её тела, он видит только название, а раз интерпретатор не заходит внутрь тела sayHi, то он понятия не имеет, что внутри мы определяем ещё одну функцию – sayGoodbye.
Далее код начинает исполняться, мы вызываем sayHi, интерпретатору PHP приходиться зайти в тело функции sayHi, чтобы выполнить её и там он случайно находит описание ещё одной функции - sayGoodbye, после чего и sayGoodbye можно вызывать в любом месте, сколько угодно раз.
Но стоит обратить внимание на очень тонкий момент в ситуации выше: функция sayHi становится одноразовой, потому что если мы ещё раз её вызовем, то PHP опять наткнётся на определение функции sayGoodbye, а в PHP так делать нельзя – нельзя переопределять функции. Об этом и о том, как с этим бороться я писал в предыдущей статье.
В PHP описанные выше приёмы применяются очень редко, чаще их можно увидеть, например, в JavaScript.
В PHP ровно две области видимости: глобальная и локальная. В каждом языке программирования области видимости устроены по-разному. Например, в C++ даже в циклах своя (локальная) область видимости. В PHP, кстати, циклы – это глобальная область видимости. Но сегодня мы говорим о функциях.
У функций в PHP своя, внутренняя область видимости (локальная), то есть все переменные внутри функции видны только внутри этой самой функции.
Итак, ещё раз: все, что вне функций – это глобальная область видимости, все, что внутри функций – локальная область видимости. Пример:
<?php
function sayHi($name){
echo 'Привет, '.$name.'! <br>';
$name = 'Рудь Сергей';
}
$name = 'Андрей';
sayHi($name);
echo $name; // ?
Уважаемые знатоки, внимание, вопрос! Что выведет последняя инструкция echo $name; ?
Ответ:
Как вы сами видели, у нас было 2 переменных $name, одна внутри функции (локальная область видимости), другая просто в коде (глобальная область видимости), последнее присвоение в переменную $name было $name = 'Рудь Сергей'; Но так как это было внутри функции, то там оно и осталось. В глобальной же области видимости последним присвоением было $name = 'Андрей'; что мы собственно и видим в результате.
То есть две одинаковые переменные, но в разных областях видимости никак не пересекаются и не влияют друг на друга.
Давайте я проиллюстрирую области видимости на рисунке:
При первом обходе интерпретатор бегло просматривает глобальную область видимости, запоминает какие есть переменные и функции, но не выполняет код.
Но что если нам всё-таки нужно из функции обратиться к той самой переменной $name из глобальной области видимости, да не просто обратиться, а изменить её? Для этого есть 3 основных варианта. Первый из них использование ключевого слова global:
<?php
function sayHi($name){
echo 'Привет, '.$name.'! <br>';
global $name; /*начиная с этого момента мы имеем ввиду
глобальную переменную $name*/
$name = 'Рудь Сергей';
}
$name = 'Андрей';
sayHi($name);
echo $name; // ?
Результат:
Но у этого способа есть минус, с тех пор как мы обратились к глобальной переменной $name мы потеряли (переписали) локальную переменную $name.
Второй способ заключается в том, чтобы использовать суперглобальный массив PHP. В этот массив PHP сам, автоматически помещает каждую переменную, которую мы создали в глобальной области видимости. Пример:
$name = 'Андрей'; //Тоже самое что и
$GLOBALS['name'] = 'Андрей';
Следовательно:
<?php
function sayHi($name){
echo 'Привет, '.$name.'! <br>';
$GLOBALS['name'] = 'Рудь Сергей';
}
$name = 'Андрей';
sayHi($name);
echo $name; // ?
Результат тот же, что и при использовании ключевого слова global:
Только в этот раз мы не переписали локальную переменную, то есть переменная $name внутри функции осталась прежней и равна "Андрей", а не "Рудь Сергей".
Третий способ – это передача адреса (ссылки) переменной, а не её значения. Ссылки в PHP не очень удались, в отличие от других языков программирования. Тем не менее, я расскажу вам единственный правильный вариант передачи аргумента по ссылке в функцию, который нормально поддерживается в PHP 5.3 и выше. Есть и другие способы работы со ссылками, но они работали в PHP 5.2 и ниже, в итоге сами разработчики PHP решили от них отказаться, поэтому не будем о них.
Так вот, ПРАВИЛЬНАЯ передача аргумента по ссылке в PHP 5.3 и выше осуществляется следующим образом:
function sayHi(&$name){
Мы в самом описании функции добавили значок амперсанд (&) – этот значок означает, что мы принимаем не значение переменной, а ссылку (адрес) на это значение в памяти. Ссылки в PHP позволяют создать две переменные, указывающие на одно и то же значение. Это означает, что при изменении одной из этих переменных, меняются обе, так как в памяти они обращаются к одному и тому же значению.
И в итоге имеем:
<?php function sayHi(&$name){ //принимаем не значение, а ссылку на значение echo 'Привет, '.$name.'! <br>'; $name = 'Рудь Сергей'; } $name = 'Андрей'; sayHi($name); echo $name; // ?
Результат:
Представьте себе следующую ситуацию: нам нужно посчитать сколько раз мы всего поздоровались. Вот что мы пытаемся сделать:
<?php
function sayHi($name){
$c = 0; // счётчик
echo 'Привет, '.$name.'! <br>';
$c++; // увеличиваем счётчик на 1
echo 'Всего поздоровались ' . $c . ' раз.<hr>';
}
sayHi('Рудь Сергей');
sayHi('Андрей');
sayHi('Дмитрий');
Результат:
Переменная $c не запоминает своего значения, она каждый раз создаётся заново. Нам нужно сделать так, чтобы наша локальная переменная $c запоминала своё значение после выполнения функции, для этого используют ключевое слово static:
<?php
function sayHi($name){
static $c = 0; // счётчик, сделали статическим
echo 'Привет, '.$name.'! <br>';
$c++; // увеличиваем счётчик на 1
echo 'Всего поздоровались ' . $c . ' раз.<hr>';
}
sayHi('Рудь Сергей');
sayHi('Андрей');
sayHi('Дмитрий');
Результат:
В функциях есть такая удобная вещь, как возврат значений. Это когда функция вместо того, чтобы вывести что-нибудь на экран, помещает всё в переменную и отдаёт эту переменную нам. А мы уже дальше решаем, что с ней делать. Для примера возьмём эту функцию, она возводит число в квадрат:
<?php
function getSquare($number){
$result = $number*$number;
echo $result;
}
getSquare(5);
Результат:
Сделаем так, чтобы вместо вывода на экран она возвращала результат выполнения. Для этого используется ключевое слово return:
<?php
function getSquare($number){
$result = $number*$number;
return $result;
}
getSquare(5);
Результат:
Теперь мы можем использовать это различными способами:
<?php
function getSquare($number){
$result = $number*$number;
return $result;
}
echo getSquare(5); //выводит результат
echo '<br>';
$num = getSquare(5); // присвоили результат в переменную
echo $num; // вывели переменную на экран
Результат:
Обращаю ваше внимание, что ключевое слово return не просто возвращает значение, а полностью прерывает работу функции, то есть весь код, который находится ниже ключевого слова return никогда не исполниться. Другими словами, return для функций вдобавок работает как break для циклов:
<?php
function getSquare($number){
$result = $number*$number;
return $result;
echo 'До меня PHP никогда не дойдёт :(';
}
echo getSquare(5); //выводит результат
echo '<br>';
$num = getSquare(5); // присвоили результат в переменную
echo $num; // вывели переменную на экран
Результат:
То есть return – это ещё и выход из функции. Его можно использовать и без возвращаемого значения, только ради выхода.
Рекурсивная функция – это функция, которая вызывает сама себя. Рекурсия используется не часто и считается ресурсоёмкой (медленной) операцией. Но бывает, что использование рекурсии самый очевидный и простой вариант. Пример:
<?php
function countPlease($number){
echo $number . '<br>';
if($number < 20){ // чтобы рекурсия не стала бесконечной
countPlease(++$number); // функция countPlease вызвала сама себя
}
}
countPlease(1);
Результат:
Если вы знаете, как обойтись без рекурсии, то лучше так и сделать.
В PHP сделаны мелкие шаги к строгой типизации, благодаря этому мы можем заранее указать, какой тип должна принимать функция (это называется type-hint):
<?php function countPlease(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:
<?php
function countPlease(callable $v){
$v();
}
countPlease("getEcho");
function getEcho(){
echo 'Вызвали функцию getEcho;
}
Callable проверяет, может ли переданное значение быть вызвано в качестве функции. Callable может быть как именем функции, заданным строковой переменной, так и объектом и именем вызываемого метода. Но про объекты и методы мы поговорим позже (это раздел объектно-ориентированного программирования), а с функциями вы уже знакомы. Результат работы я вам показать не могу, так как у меня сейчас стоит PHP 5.3, но он был бы:
Вызвали функцию getEcho
И напоследок ещё один очень редко используемый нюанс. Представьте ситуацию, мы передаём в функцию аргументы, хотя в функции мы их не описали, например:
<?php
function getEcho(){
echo 'Вызвали функцию getText';
}
$age = 22;
getEcho('Рудь Сергей', $age);
Результат:
Как видите, ошибок нет, но и наши переданные аргументы нигде не используются. Но это не значит, что они пропали – они всё равно передались в функцию и мы можем их использовать, для этого существуют встроенные функции PHP:
func_num_args() - Возвращает количество аргументов, переданных функции
func_get_arg(порядковый номер) - Возвращает элемент из списка аргументов
func_get_args() - Возвращает массив, содержащий аргументы функции
Пример:
<?php
function getEcho(){
echo 'Вызвали функцию getText <br>';
echo func_get_arg(0);
}
$age = 22;
getEcho('Рудь Сергей', $age);
Результат:
Сегодняшняя статья является заключительной по теме функций в PHP. Теперь вы можете быть уверены в полноте своих знаний касательно этой темы и можете смело использовать функции для своих нужд.
Если у кого-то есть желание набить руку, но нет идей как это сделать – лучшим способом будет написание уже готовых (встроенных) функций PHP, например, можно написать собственную функцию count() или любую другую.
Благодарю всех за внимание и до новых встреч! Если что-то не понятно, смело задавайте ваши вопросы в комментариях!
Пожалуйста, прокомментируйте, как Вам моя статья?