Обращение к функциям через переменные. Функции Написать и удалить функцию на php

Всем доброго времени суток. На связи Алексей Гулынин. В прошлой статье вы узнали, как перебрать массив в php . В данной статье я бы хотел рассказать об одной из важнейших тем — это функции в php . Синтаксис определения функции в общем виде такой:

Function myFunction(arg1 = знач1, arg2 = знач2,..., argn = значn) { //тело функции }

Объявление функции начинается с ключевого слова function . Далее идёт название функции (название не зависит от регистра букв). Затем в скобках указываются параметры функции. Параметры могут быть как со значениями (параметры по умолчанию), так и без них. Также в функции могут отсутствовать параметры вовсе. После задания параметров, в квадратных скобках (тело функции) содержится вся логика работы функции, т.е. все операторы.

Если функция должна возвращать какое-то значение, то используется ключевое слово return . Функция также может и ничего не возвращать. В PHP return можно использовать для абсолютно любых объектов. Давайте напишем функцию, которая возвращает куб аргумента:

"; //выведет 27 echo cubeNumber(4)."
"; //выведет 64 ?>

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

Все переменные, которые описаны в теле функции, являются локальными. Они существуют только в теле функции и перестают существовать после окончания функции. Давайте напишем простой пример:

"; $a = $a + 10; echo "Конечное значение (в функции) = $a
"; } $a = 20; echo "Начальное значение = $a
"; addTen($a); echo "Конечное значение = $a"; //выведет также 20, увеличения не будет?>

Для того, чтобы значение изменилось, необходимо передавать ссылку function addTen(&$a). После этого, в конце мы увидим, что выведено число 30.

Иногда мы не знаем сколько будет параметров у функции. Мы хотим, чтобы количество параметров было любым. Пример: создадим функцию, которая выводит все значения, которые ей были переданы:

"; } } vivod("Aleksey", "Ivan", "Olesya"); ?>

Функция func_get_args() возвращает список всех аргументов, указанных при вызове функции.

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

Проверить существует ли функция можно с помощью другой функции (тавтология) function_exists() , которая возвращает true, если функция существует:

В конце приведу несколько советов по использованию функций:

1) Прежде чем написать функцию, посмотрите документацию, может быть такая функция уже есть.

2) Функция должна быть компактной, она не должна иметь большие размеры. Обычно функция должна быть в 20-30 строк. Где-то ещё слышал, что вся функция должна умещаться на экран

Функция - это именованный блок кода, в данном случае на языке PHP, который определяется один раз, а затем может вызываться на исполнение сколько угодно раз.

Определение функции выполняется с помощью ключевого слова function за которым указываются следующие компоненты:

  • Идентификатор , определяющий имя функции. Он будет использован для создания новой переменной, которой будет присвоена функция. Имена функций следуют тем же правилам, что и именование переменных.

    Примечание: имена функций не чувствительны к регистру букв.

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

Синтаксис определения функции выглядит следующим образом:

Function имя_функции([параметры]) { блок кода }

Квадратные скобки () означают необязательность. Теперь приведем простой пример определения функции:

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

При вызове функции исполняются инструкции, расположенные в ее теле.

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

Все функции в PHP имеют глобальную область видимости - они могут быть вызваны вне функции, даже если были определены внутри и наоборот:

Чаще всего функции работают с каким-либо переданными ей значениями. Для того, чтобы функции можно было передать некоторые значения, в ней должны быть указаны параметры. Эти параметры по сути являются обычными переменными, которые инициализируются переданными значениями при вызове функции.

Последнее обновление: 1.11.2015

Функции представляют собой набор инструкций, выполняющих определенное действие.

Синтаксис определения функции:

Function имя_функции([параметр [, ...]]) { // Инструкции }

Определение функции начинается с ключевого слова function , за которым следует имя функции. Имя функции должно начинаться с алфавитного символа или подчеркивания, за которыми может следовать любое количество алфавитно-цифровых символов или символов подчеркивания.

После имени функции в скобках идет перечисление параметров. Даже если параметров у функции нет, то просто идут пустые скобки. Затем в фигурных скобках идет тело функции, содержащее набор инструкций.

Определим простейшую функцию:

Function display() { echo "вызов функции display()"; }

Данная функция не имеет параметров и все, что она делает - это вывод на страницу некоторого сообщения.

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

Возвращение значения и оператор return

Функция может возвращать некоторое значение - число, строку и т.д., то есть некоторый результат. Для возвращения значения в функции применяется оператор return , после которого указывается возвращаемое значение. Например:

Функция get() возвращает число, представляющее сумму квадратов от 1 до 9. Это число хранится в переменной $result . Благодаря оператору return мы можем присвоить значение, возвращаемое функцией get, какой-нибудь переменной: $a = get(); .

Использование параметров

Создадим функцию с параметрами:

Так как теперь функция $get использует параметры, то мы должны передать при вызове этой функции на место параметров некоторые значения. Если при вызове мы укажем значения не для всех параметров, то это будет ошибка, например: $a = get(1); .

Но мы можем использовать значения по умолчанию для параметров. Например:

В этом случае, если мы не укажем значение для второго параметра, то по умолчанию он будет равен 10.

Передача по ссылке

В примере выше мы передавали параметры по значению . Но в PHP есть и другая форма передачи параметров - по ссылке . Рассмотрим два этих способа передачи параметров и сравним. Стандартная передача параметра по значению:

\$number равно: $number"; function get($a) { $a*=$a; echo "Квадрат равен: $a"; } ?>

После вызова функции get() значение переменной $number не изменится, так как в эту функцию в качестве параметра мы передаем значение переменной.

\$number равно: $number"; function get(&$a) { $a*=$a; echo "Квадрат равен: $a"; } ?>

При передаче по ссылке перед параметром ставится знак амперсанда: function get(&$a) . Теперь интерпретатор будет передавать не значение переменной, а ссылку на эту переменную в памяти, в итоге, переменная $number после передачи на место параметра &$a также будет изменяться.

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

1. Создание функций с переменным числом аргументов

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

Но для начала, вспомним как мы создаём функции обычным образом:

// функция с двумя необязательными параметрами function foo($arg1 = "", $arg2 = "") { echo "arg1: $arg1\n"; echo "arg2: $arg2\n"; } foo("hello","world"); /* выведет: arg1: hello arg2: world */ foo(); /* выведет: arg1: arg2: */

Теперь посмотрим на то, как можно написать функцию с неограниченным количеством аргументов. Для этого будет использовать метод func_get_args() :

// не указываем аргументы function foo() { // возвращает массив, переданных аргументов $args = func_get_args(); foreach ($args as $k => $v) { echo "arg".($k+1).": $v\n"; } } foo(); /* ничего не выведет */ foo("hello"); /* выведет arg1: hello */ foo("hello", "world", "again"); /* выведет arg1: hello arg2: world arg3: again */

2. Используем Glob() для поиска файлов

Часто названия функций говорят сами за себя. Такого нельзя сказать о функции glob() .

Если не вдаваться в подробности, её функциональность схожа с методом scandir() . Она позволяет найти необходимый файл по шаблону:

// найти все php файлы $files = glob("*.php"); print_r($files); /* выведет: Array ( => phptest.php => pi.php => post_output.php => test.php) */

Для нахождения файлов нескольких типов надо писать так:

// найти все php и txt файлы $files = glob("*.{php,txt}", GLOB_BRACE); print_r($files); /* на выходе: Array ( => phptest.php => pi.php => post_output.php => test.php => log.txt => test.txt) */

Так же можно в шаблоне указать путь:

$files = glob("../images/a*.jpg"); print_r($files); /* на выходе: Array ( => ../images/apple.jpg => ../images/art.jpg) */

Для того чтобы получить полный путь к документу используйте метод realpath() :

$files = glob("../images/a*.jpg"); // Применить функцию "realpath" к каждому элементу массива $files = array_map("realpath",$files); print_r($files); /* выведет: Array ( => C:\wamp\www\images\apple.jpg => C:\wamp\www\images\art.jpg) */

3. Информация об используемой памяти

Если вы будете отслеживать количество памяти, которое съедается на работу ваших скриптов то, наверное, чаще будете их оптимизировать.

В PHP существует мощный инструмент отслеживания используемой памяти. В разных частях скрипта нагрузки могут быть разные. Для того чтобы получить значение используемой памяти в данный момент, нам следует использовать метод memory_get_usage() . Для фиксации максимального количества используемой памяти используем memory_get_peak_usage()

Echo "Initial: ".memory_get_usage()." bytes \n"; /* Initial: 361400 bytes */ // дадим небольшую нагрузку for ($i = 0; $i < 100000; $i++) { $array = md5($i); } // и ещё for ($i = 0; $i < 100000; $i++) { unset($array[$i]); } echo "Final: ".memory_get_usage()." bytes \n"; /* Final: 885912 bytes */ echo "Peak: ".memory_get_peak_usage()." bytes \n"; /* Peak: 13687072 bytes */

4. Информация о процессоре

Для этого необходимо использовать метод getrusage() . Но учтите, что на Windows эта функция работать не будет.

Print_r(getrusage()); /* prints Array ( => 0 => 0 => 2 => 3 => 12692 => 764 => 3864 => 94 => 0 => 1 => 67 => 4 => 0 => 0 => 0 => 6269 => 0) */

Картина, изложенная выше, будет понятно тем, у кого есть опыт в системном администрировании. Для всех остальных предлагаем расшифровку:

  • ru_oublock: количество операций блочной записи
  • ru_inblock: количество операций блочного чтения
  • ru_msgsnd: количество отправленных сообщений
  • ru_msgrcv: количество принятых сообщений
  • ru_maxrss: максимальный размер невыгружаемого набора
  • ru_ixrss: общий объем разделяемой памяти
  • ru_idrss: общий объем неразделяемых данных
  • ru_minflt: количество используемых страниц памяти
  • ru_majflt: количество ошибок отсутствия страниц
  • ru_nsignals: количество принятых сигналов
  • ru_nvcsw: количество переключений контекста процессом
  • ru_nivcsw: количество принудительных переключений контекста
  • ru_nswap: количество обращений к диску при подкачке страниц
  • ru_utime.tv_usec: время работы в пользовательском режиме (микросекунды)
  • ru_utime.tv_sec: время работы в пользовательском режиме (секунды)
  • ru_stime.tv_usec: время работы в привилегированном режиме (микросекунды)
  • ru_stime.tv_sec: время работы в привилегированном режиме (секунды)

Для того чтобы узнать какие ресурсы вашего процессора используются скриптом, вам необходимо значение ‘user time’ (время работы в пользовательском режиме) и ’system time’ (время работы в привилегированном режиме). Вы можете получить результат как в секундах, так и в микросекундах. Для того чтобы превратить общее количество секунд в десятичное число, вам необходимо разделить значение микросекунд на 1 миллион и добавить к значению секунд.

Запутанно как-то. Вот пример:

// отдыхаем 3 секунды sleep(3); $data = getrusage(); echo "User time: ". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "System time: ". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* выводит User time: 0.011552 System time: 0 */

Хотя выполнение скрипта заняло около 3-х секунд, процессор не был сильно нагружен. Дело в том, что при вызове (sleep) скрипт практически не потребляет ресурсов процессора. Вообще существует множество задач, которые занимают значительное время, но при этом не используют процессор. К примеру, ожидание операций связанных с диском. Так что вы не всегда используете процессорное время в своих скриптах.

Вот ещё пример:

// пройтись 10 миллионов раз for($i=0;$i<10000000;$i++) { } $data = getrusage(); echo "User time: ". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "System time: ". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* выводит User time: 1.424592 System time: 0.004204 */

Работа скрипта заняла 1.4 секунды процессорного времени. В данном случае, время системных вызовов вообще низкое.

Время работы в привилегированном режиме (System Time) - это время, которое процессор затрачивает на выполнение системных запросов к ядру от имени программы. Пример:

$start = microtime(true); // вызываем microtime каждые 3 секунды while(microtime(true) - $start < 3) { } $data = getrusage(); echo "User time: ". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "System time: ". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* выводит User time: 1.088171 System time: 1.675315 */

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

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

5. Магические константы

В PHP существует множество магических констант, таких как номер текущей строки (__LINE__), путь к файлу (__FILE__), путь к каталогу (__DIR__), имя функции (__FUNCTION__), имя класса (__CLASS__), имя метода (__METHOD__) и пространства имён (__NAMESPACE__).

Все мы их рассматривать не будем. Посмотрим только лишь парочку:

// этот скрипт зависит от текущего расположения файла и // может вызвать проблемы, если его использовать из разных дирректорий require_once("config/database.php"); // этот скрипт не вызовет проблем require_once(dirname(__FILE__) . "/config/database.php");

Используйте __LINE__ при отладке скриптов:

// код // ... my_debug("some debug message", __LINE__); /* выведет Line 4: some debug message */ // ещё код // ... my_debug("another debug message", __LINE__); /* выведет Line 11: another debug message */ function my_debug($msg, $line) { echo "Line $line: $msg\n"; }

6. Генерирование уникальных ID

Бывают такие моменты, когда вам надо сгенерировать уникальную строку. Множество раз я видел, что для решения этой задачи используют функцию md5():

// генерируем случайную строку echo md5(time() . mt_rand(1,1000000));

Но на самом деле для этих целей в PHP есть специальная функция uniqid()

// генерируем случайную строку echo uniqid(); /* выведет 4bd67c947233e */ // ещё разок echo uniqid(); /* выведет 4bd67c9472340 */

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

Для того чтобы уменьшить шансы получения дубликата, мы можем добавить префикс или использовать второй параметр (увеличит количество символов):

// с префиксом echo uniqid("foo_"); /* выведет foo_4bd67d6cd8b8f */ // со вторым параметром echo uniqid("",true); /* выведет 4bd67d6cd8b926.12135106 */ // оба echo uniqid("bar_",true); /* выведет bar_4bd67da367b650.43684647 */

Этот метод генерирует строки размером меньше, чем md5, тем самым вы сможете сэкономить место.

7. Сериализация

Вам когда-нибудь приходилось хранить комплексные данные в базе или в файле? Для того чтобы сконвертировать объект в строку в PHP предусмотрена специальная функция.

Вообще говоря, этих методов 2: serialize() и unserialize()

// сложный массив $myvar = array("hello", 42, array(1,"two"), "apple"); // конвертируем в строку $string = serialize($myvar); echo $string; /* выведет a:4:{i:0;s:5:"hello";i:1;i:42;i:2;a:2:{i:0;i:1;i:1;s:3:"two";}i:3;s:5:"apple";} */ // получаем исходное значение $newvar = unserialize($string); print_r($newvar); /* выведет Array ( => hello => 42 => Array ( => 1 => two) => apple) */

Вот так вот работают эти функции. Однако из-за бурного роста популярности JSON, в PHP 5.2 были добавлены 2 метода json_encode() и json_decode(). Их работа схожа с serialize():

// сложные массив $myvar = array("hello", 42, array(1,"two"), "apple"); // конвертируем в строку $string = json_encode($myvar); echo $string; /* выведет ["hello",42,,"apple"] */ // восстанавливаем исходное значение $newvar = json_decode($string); print_r($newvar); /* prints Array ( => hello => 42 => Array ( => 1 => two) => apple) */

Этот вариант более компактный и совместимый с другими языками, такими как JavaScript. Однако при работе с очень навороченными объектами может возникнуть потеря данных.

8. Сжатие строк

Кода мы говорим о сжатии, то на ум сразу же приходят архивные файлы в формате ZIP. PHP предоставляет возможность сжатия длинных строк без всяких файлов.

В следующем примере продемонстрируем работу функций gzcompress() и gzuncompress() :

$string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut elit id mi ultricies adipiscing. Nulla facilisi. Praesent pulvinar, sapien vel feugiat vestibulum, nulla dui pretium orci, non ultricies elit lacus quis ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam pretium ullamcorper urna quis iaculis. Etiam ac massa sed turpis tempor luctus. Curabitur sed nibh eu elit mollis congue. Praesent ipsum diam, consectetur vitae ornare a, aliquam a nunc. In id magna pellentesque tellus posuere adipiscing. Sed non mi metus, at lacinia augue. Sed magna nisi, ornare in mollis in, mollis sed nunc. Etiam at justo in leo congue mollis. Nullam in neque eget metus hendrerit scelerisque eu non enim. Ut malesuada lacus eu nulla bibendum id euismod urna sodales. "; $compressed = gzcompress($string); echo "Original size: ". strlen($string)."\n"; /* выведет Original size: 800 */ echo "Compressed size: ". strlen($compressed)."\n"; /* выведет Compressed size: 418 */ // возвращаем $original = gzuncompress($compressed);

В наших силах уменьшить объём текста на 50%. В этих же целях можно использовать методы gzencode() и gzdecode(), которые используют другой алгоритм сжатия.

9. Выполнить перед завершением

В PHP существует функция register_shutdown_function() , которая позволит вам выполнить какой-то код перед завершением работы скрипта.

Допустим, вы хотите узнать какую-то информацию… Время работы скрипта:

// получаем время начала $start_time = microtime(true); // какие-то операции // ... // выводим время работы echo "execution took: ". (microtime(true) - $start_time). " seconds.";

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

При использовании метода register_shutdown_function() код выполнится в любом случае:

$start_time = microtime(true); register_shutdown_function("my_shutdown"); function my_shutdown() { global $start_time; echo "execution took: ". (microtime(true) - $start_time). " seconds."; }

Вывод

PHP это целая планета, которая не перестаёт нас удивлять своим содержимым. А что думаете вы о данных функциях?

Чтобы писать на языке PHP программы, представляющие из себя нечто большее, чем просто пара страниц кода, и при этом достаточно удобно организованные, понадобится освоить понятие функции. Функции избавят вас от многократного повторения одних и тех же фрагментов кода в программах. Чтобы получить функцию, нужно назначить фрагменту кода имя, называемое именем функции. После этого данный фрагмент можно исполнять, обращаясь к нему по этому имени.

Основная синтаксическая структура, обеспечивающая использование (или вызов) функции, показана ниже:

Function_name(expression_1, expression_2, ... ,expression_n)

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

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

В PHP есть сотни встроенных функций. Все приведенные ниже примеры представляют собой допустимые вызовы встроенных функций PHP:

Вызов встроенных функций PHP sqrt(9); // Вызов функции вычисления квадратного корня, который // приводит к получению значения 3 rand(10, 10 + 10); // Возвращает случайное число от 10 до 20 strlen("В этой строке 24 символа"); // Возвращает значение 24 pi(); // Возвращает приближенное значение числа "пи"

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

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

Код PHP $my_pi = pi();

Еще один вариант состоит в том, что полученный результат может вкладываться в более сложные выражения, как в следующем примере:

Код PHP $approx = sqrt($approx) * sqrt($approx);

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

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

Определение собственных функций

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

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

Определения функций имеют следующую форму:

Function function-name ($argument-1, $argument-2, ..) { statement-1; statement-2; ... }

Это означает, что определения функций состоят из перечисленных ниже четырех частей:

    Ключевое слово function .

    Имя, которое должно быть присвоено функции.

    Список параметров функции - имена переменных с префиксом в виде знака доллара, разделенные запятыми (параметры могут отсутствовать).

    Тело функции - набор операторов, заключенный в фигурные скобки.

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

Ниже кратко описаны действия, происходящие при вызове определяемой пользователем функции:

    Интерпретатор PHP выполняет поиск функции по имени (если функция еще не была определена, то активизируется ошибка).

    Интерпретатор PHP подставляет значения параметров вызова (или фактических параметров) вместо переменных в списке параметров определения (или формальных параметров).

    Выполняются операторы из тела функции. Если какой-либо из выполняемых операторов представляет собой оператор return , функция останавливается и возвращает требуемое значение. В противном случае функция завершает свою работу после выполнения последнего оператора, не возвращая какого-либо значения.

Пример определения функции

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

Код PHP $liters_1 = 1.0; $price_1 = 1.59; $liters_2 = 1.5; $price_2 = 2.09; $per_liter_1 = $price_1 / $liters_1; $per_liter_2 = $price_2 / $liters_2; if ($per_liter_1 < $per_liter_2) print("Первая сделка лучше!

")

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

Код PHP // Определение функции function better_deal ($amount_1, $amount_2, $price_1, $price_2) { $per_amount_1 = $price_1 / $amount_1; $per_amount_2 = $price_2 / $amount_2; // Возврат какого-то значения из функции return ($per_amount_1 < $per_amount_2); } $liters_1 = 1.0; $price_1 = 1.59; $liters_2 = 1.5; $price_2 = 2.09; // Вызов функции в условном операторе if (better_deal($liters_1, $liters_2, $price_1, $price_2)) print("Первая сделка лучше!
"); else print ("Вторая сделка лучше!
")

Функция better_deal представляет в общем виде три строки предыдущего кода, в котором выполняются арифметические операции и операции сравнения. Эта функция принимает в качестве фактических параметров четыре числа и возвращает логическое выражение. Как и в случае любого логического значения, полученное значение можно вложить в ту часть оператора if, в которой выполняется сравнение.

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

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

Код PHP // Определение функции function better_deal ($amount_1, $amount_2, $price_1, $price_2) { $per_amount_1 = $price_1 / $amount_1; $per_amount_2 = $price_2 / $amount_2; // Возврат значения из функции не происходит, // но выполняются какие-то действия if ($per_amount_1 < $per_amount_2) print("Первая сделка лучше!
"); else print ("Вторая сделка лучше!
"); } // Вызов функции better_deal(1.0, 1.5, 1.59, 2.09);

В первой функции используется оператор return для возврата логического результата, применяемого в дальнейшем в проверке оператора if. Во второй функции оператор return отсутствует, поскольку эта функция используется для получения побочного эффекта, который сводится к выводу текста в браузер пользователя. После выполнения последнего оператора данной функции интерпретатор PHP просто переходит к выполнению следующего оператора, который следует за вызовом функции.

Использование меньшего количества параметров

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

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

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

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

    На время изменить значение степени серьезности ошибок, применительно к которым активизируются сообщения об ошибках в сценарии, с помощью такого оператора:

    Код PHP error_reporting(E_ALL - (E_NOTICE + E_WARNING));

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

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

    Код PHP ... // Вызов функции с 2мя параметрами вместо 4 @better_deal(1.0, 1.5);

Функции и область определения переменных

Про область определения переменных и описание локальных, глобальных, суперглобальных и статических переменных мы говорили в статье "Переменные и константы" ранее. Напомню, любая переменная объявленная внутри функции является локальной, ее можно сделать глобальной за счет использования ключевого слова global. Статические переменные используются внутри функции и сохраняют свое значение между вызовами этой функции. Суперглобальные переменные, представленные в виде массивов, доступны повсеместно.

Область определения функции

Безусловно, правила, касающиеся области определения имен переменных, довольно просты, а правила формирования области определения имен функций еще проще. В версии PHP5 предусмотрено только одно правило: функция должна быть определена один (и только один) раз в том сценарии, в котором она используется. Область определения имен функций неявно рассматривается как глобальная, поэтому функция, определенная в сценарии, доступна в любом месте этого сценария. Но для упрощения изучения кода часто рекомендуется определять функции еще до того, как они будут вызываться в коде.

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

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

Код PHP // Вызываем функцию sum() до ее определения echo sum(15, 26); function sum($a, $b) { return $a + $b; }

Рекурсия

Некоторые компилируемые языки, такие как C и C++, налагают довольно сложные ограничения по упорядочению кода, касающиеся того, как должны быть заданы определения функций. Дело в том, что для получения информации о том, как компилировать функцию, компилятор должен знать обо всех функциях, вызываемых в данной функции, а это означает, что вызываемые функции должны быть определены в первую очередь. Так что же делать, если две функции вызывают друг друга или одна функция вызывает саму себя?

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

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

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

Код PHP function countdown($count) { if ($count > 0) { echo "Число $count
"; // Рекурсия countdown(--$count); } } countdown(10);

В результате в окне браузера отображается следующий вывод:

Пример использования рекурсии в PHP

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

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

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

Код PHP function countdown_first($count) { if ($count > 0) { echo "Вызов функции countdown_first: $count
"; // Рекурсия на другую функцию countdown_second(--$count); } } function countdown_second($count) { if ($count > 0) { echo "Вызов функции countdown_second: $count
"; // Рекурсия на другую функцию countdown_first(--$count); } } countdown_first(5);

приводит к получению в окне браузера такого вывода:


Взаимно рекурсивные функции

Переменное количество параметров

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

  • Определить функцию с параметрами, заданными по умолчанию. Всем параметрам, отсутствующим в вызове функции, будет присваиваться заданное по умолчанию значение, поэтому не появится предупреждающее сообщение об отсутствии необходимых параметров.

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

    Использовать функции с переменным количеством параметров (func_num_args(), func_get_arg() и func_get_args()).

В следующих разделах каждая из этих возможностей рассматривается отдельно.

Параметры, заданные по умолчанию

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

Например, в следующей функции все параметры определены со значениями, заданными по умолчанию:

Код PHP function tour_guide($city = "Москва", $desc = "большой мегаполис", $how_many = "14 млн.") { print("$city

"); } tour_guide(); tour_guide("Комарово"); tour_guide("Комарово", "маленькая деревня"); tour_guide("Комарово", "маленькая деревня", "40");

В окне браузера формируется примерно такой вывод, как показано ниже:


Переменное количество параметров при вызове функции

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

Использование массивов для замены многочисленных параметров

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

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

Код PHP function tour_brochure($arr) { $city = isset($arr["city"]) ? $arr["city"] : "Москва"; $desc = isset($arr["desc"]) ? $arr["desc"] : "большой мегаполис"; $how_many = isset($arr["how_many"]) ? $arr["how_many"] : "14 млн."; print("$city это $desc в котором проживает $how_many человек.

"); } // Пустой массив tour_brochure(array()); // Массив со значениями $tour = array("city" => "Комарово", "desc" => "маленькая деревня", "how_many" => 40); tour_brochure($tour);

В этой функции проверяется наличие в одном входном параметре, представленном в виде массива, трех различных значений, связанных с конкретными строками. С использованием трехместной условной операции (?:) локальным переменным присваивается либо входящее значение (если оно записано в массив), либо заданные по умолчанию фрагменты текста. В этом примере функция tour_brochure вначале вызывается с пустым массивом (который соответствует ситуации с отсутствием фактических параметров), а затем с массивом, в котором хранятся три значения элементов ассоциативного массива.

Использование многочисленных параметров

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

Функция func_num_args()

He принимает параметров и возвращает данные о количестве параметров, переданных в функцию, из которой она вызвана.

Функция func_get_arg()

Принимает целочисленный параметр n и возвращает n-й параметр в функцию, из которой она вызвана. Нумерация параметров начинается с нуля.

Функция func_get_args()

Не принимает параметров и возвращает массив, содержащий все параметры функции, из которой она вызвана, индексы этого массива начинаются с нуля.

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

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

В качестве примера рассмотрим функцию, в которою можно передавать любое количество чисел и которая высчитывает их сумму:

Код PHP function Sum() { $sum = 0; for ($i = 0; $i < func_num_args(); $i++) { $sum += func_get_arg($i); } return $sum; } echo "5 + 120 + 8 = ".Sum(5, 120, 8); echo "
10 - 18 + 104 + 2 = ".Sum(10, -18, 104, 2);

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

Вызов по значению

По умолчанию определяемые пользователем функции в языке PHP действуют на основе вызова по значению. Под этим подразумевается, что при передаче параметров в вызов функции интерпретатор PHP создает копию значений этих параметров для последующей передачи в функцию. Поэтому любые действия, выполняемые в функции, не позволяют изменить значения фактических параметров, присутствующих в вызове функции.

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

Одно из наиболее важных различий между версией PHP5 и предшествующими ей версиями состоит в том, что в ней экземпляры объектов фактически всегда передаются по ссылке, даже при том, что любые параметры другого типа передаются по значению. Это связано с тем, что в версии PHP5 переменные типа "объект" хранят дескрипторы объектов, а не сами объекты, поэтому в режиме передачи параметров по значению фактически копируются сами дескрипторы, а не основополагающие объекты (более подробное обсуждение этого вопроса будет дано в разделе по объектно-ориентированному программированию в PHP).

Ниже приведен пример очень простой функции, увеличивающей переданное ей в параметре число на 10:

Код PHP \$number = $number
"; function add10($a) { $a += 10; echo "Вызов функции add10() ... , результат: $a
\$number

Как видно из показанного ниже скриншота, вызов функции не повлиял на значение самой переменной $number и она осталась равна 20:


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

Вызов по ссылке

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

Если необходимо определить функцию, действие которой непосредственно распространяется на переданный параметр, достаточно поместить символ амперсанда перед формальным параметром в определении функции, как показано ниже:

Код PHP $number = 20; echo "Изначально \$number = $number
"; function add10(&$a ) { $a += 10; echo "Вызов функции add10() ... , результат: $a
"; return $a; } add10($number); echo "Значение \$number после вызова функции add10(): $number";

Теперь, после выполнения точно такого же вызова функции переменная $number изменяется и будет равна 30:


Передача параметров функции по ссылке

Дело в том, что в данном случае формальный параметр $a ссылается на переменную $number, поэтому его модификация в функции приводит к изменению переменной $number.

Начиная с версии PHP4 ссылки на переменные могут также использоваться вне вызовов функции. Вообще говоря, в результате присваивания переменной ссылки на переменную (например, &$varname) имена этих двух переменных становятся псевдонимами по отношению друг к другу, а не отдельными переменными с тем же значением. Рассмотрим пример:

Код PHP $name_1 = "Александр"; $name_2 = "Игорь"; // Передача переменной по значению $alias_1 = $name_1; // Передача переменной по ссылке $alias_2 = &$name_2; // Изменение переменной $alias_1 не приводит к изменению $name_1 $alias_1 = "Дмитрий"; echo "\$alias_1 = $alias_1, \$name_1 = $name_1

"; // Изменение переменной $alias_2 приводит к изменению $name_2 // т.к. они взаимосвязаны через ссылку $alias_2 = "Петр"; echo "\$alias_2 = $alias_2, \$name_2 = $name_2

";

который приводит к получению в окне браузера следующего вывода:


Передача переменной по ссылке

Переменные в качестве функций

Один из еще более утонченных приемов, которые могут использоваться в языке PHP, состоит в применении переменных в позиции имен функций, определяемых пользователем. Это означает, что вместо ввода в коде литерального имени функции можно ввести переменную со знаком доллара. В таком случае то, какая функция будет фактически вызвана на этапе прогона, зависит от содержимого строки, присвоенной данной переменной.

В определенном смысле это позволяет использовать функции в качестве данных. Подобный прием должен быть знаком квалифицированным программистам, работающим на языке C, и даже начинающим пользователям, которые применяют какую-либо разновидность языка Lisp (например, Scheme или Common Lisp). В частности, два приведенных ниже вызова функции полностью эквивалентны:

Код PHP function sum($a, $b) { return $a + $b; } echo sum(10, 15)."
"; // Передаем переменной функцию и вызываем ее $var = "sum"; echo $var(12, 14);

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

Циклы Обработка строк 1 2 3 4 5 6 7 8 9 10

Похожие статьи