php функции


Содержание

Создание функций в PHP

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

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

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

Область видимости переменных

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

Суперглобальные массивы

$_SERVER , $_SESSION , $_COOKIE и другие — это суперглобальные массивы. Их данные доступны в любом месте сценария. Вот лишь несколько из них:

  • $_SERVER[‘REMOTE_ADDR’] — IP-адрес пользователя;
  • $_SERVER[‘SERVER_NAME’] — имя сервера;
  • $_SERVER[‘DOCUMENT_ROOT’] — корневой каталог сайта;
  • $_SERVER[‘REQUEST_URI’] — запрошенный адрес документа.

Аргументы функции

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

Необязательные параметры (параметры по умолчанию) функции

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

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

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

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

Одной из главный особенностей функций является их способность возвращать результат. Не всегда в сценарии необходимо что-то делать с результатом работы функции. Чаще его нужно просто сохранить и использовать в другом месте сценария совсем для других целей[?] собственно, для вывода некоего значения на экран функции вообще практически никогда не используются. . Для того, чтобы функция вернула значение в то место сценария, из которого она была вызвана, необходимо воспользоваться оператором return . Любой код, который следует за оператором return , не выполняется (если оператор return сработал как надо).

PHP: Функции

Автор: Артемьев Сергей Игоревич
ICQ: 438856621
email: _spin_@bk.ru

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

Функции бывают пользовательские и системные. Пользовательские функции (как следует из названия) программист пишет самостоятельно. Системные функции всегда доступны из любого места скрипта и объявлять их не надо.

Пользоваться функциями очень просто. Объявляется функция следующим образом:

Любая функция имеет имя, список параметров, тело функции и возвращаемые данные. Правила именования функций аналогичны правилам дя переменных. Параметры записываются в скобках через запятую, а если функции не требуются параметры — должны ставится пустные скобки «()». Любая функция должна возвращать какое-либо значение. Если в коде функции не встречается выражение return, то считается, что функция возвращает пустое значение. Немаловажный факт — в PHP тип возвращаемых данных заранее не определён. Поэтому одна функция может возвращать значения с различными типами данных в зависимости от входных параметров.

Теперь в любом месте скрипта можно написать

и в браузер будет выведено

Рассмотрим более интересный вариант применения — функцию преобразования данных. Например, у нас есть список, содержащий полные имена, фамилии и отчества сотрудников. Нам для составления отчёта надо преобразовать полное ФИО к формату фамилии с инициалами, т.е. преобразовать «Иванов Александр Владимирович» в «Иванов А.В.».

Функция для преобразования будет выглядеть так:

а код для вызова функции будет выглядеть так:

При использовании функций необходимо помнить следующее:

  1. В теле функции используются копии параметров, поэтому все изменения переменных будут потеряны привыходе из функции. Мы уже рассматривали такой пример при изучении областей видимости переменных.
  2. Если параметр должен быть изменён в функции — необходимо передавать его по ссылке, т.е. в описании функции надо перед именем параметра добавить «&»: function func($p1, &$p2)
  3. В старых версиях PHP функция должна была быть объявлена до первого использования, но в PHP версии 4.3 и выше порядок объявления и использования функции может быть любым.

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

лабы по информатике, егэ

лабораторные работы и задачи по программированию и информатике, егэ по информатике

PHP занятие 5. Функции языка

Встроенные php функции

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

Все функции языка PHP подразделяются на:

Встроенные функции — это предусмотренные синтаксисом языка конструкции, выполняющие конкретные действия. Примером могут служить рассмотренные ранее функции echo() и print() .

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

Что необходимо знать про любые функции:

  • после названия функции всегда ставятся круглые скобки (могут быть пустые или с аргументами функции внутри, перечисленными через запятые);
  • функция может принимать информацию из программы через список аргументов, разделенных запятыми (аргументы читаются слева направо);
  • если в функцию передаются аргументы не того типа, на который она «рассчитывает» (например string вместо array ), то будет выдаваться либо NULL либо ошибка;
  • для вызова функции достаточно написать ее имя и список фактических аргументов в круглых скобках.

Рис. 5.1. Пример использования встроенных функций php

PHP пользовательские функции

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

// описание функции function sayHello()< echo "Привет!
«; > // вызов функции sayHello(); // проверка существования функции if (function_exists(«sayHello»))

Результат:

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

Результат:

Пример иллюстрирует, что средства php не позволяют создавать локальных функций, т.е. которые будут «видны» только в определенных местах кода программы. В нашем случае function2() должна быть локальной, т.е. область ее видимости — только функция function1() . Вызывая локальную функцию из общей программы, должна выдаваться ошибка. Но в php данный механизм отсутствует, и ошибки нет. Таким образом обе функции в примере глобальные.

Создание функции php с аргументами

Рассмотрим синтаксис функции с аргументами на примере

// описание функции function sayHello($name)< echo "Привет, $name!
«; > // вызов функции вариант 1 sayHello(«Вася»); // вызов функции вариант 2 $name=»Вася»; sayHello($name); // вызов функции вариант 3 $myFunc=»sayHello»; // здесь круглые скобки не нужны! $myFunc(«Вася»);

Все три способа вызова функции равнозначны.

Примечание: степень в php вычисляется при помощи функции pow()
pow ($a, $b); где $a — число, $b — степень

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

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

Рис. 5.2. Локальные и глобальные переменные в php

Рис. 5.3. Передача аргумента по ссылке

function add_str(&$str2) < $str2 .= 'и кое-что еще.'; >$str1 = ‘Просто строка, ‘; add_str($str1); echo $str1; // выведет ‘Просто строка, и кое-что еще.’

  1. Опишите функцию getTable()
  2. Задайте для функции три аргумента: cols , rows , color

Задание 2

  1. Скопируйте код, отрисовывающий таблицу умножения из лабораторной работы предыдущего урока
  2. Вставьте скопированный код в тело функции getTable()
  3. Измените код таким образом, чтобы таблица отрисовывалась в зависимости от входящих параметров cols , rows и color

Задание 3

Отрисуйте таблицу умножения вызывая функцию getTable() с различными параметрами

Аргументы по умолчанию

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

Рис. 5.4. Значение по умолчанию

function sayHello($p,$name = «Гость»)< echo "$p, $name!
«; > sayHello(«Привет»,»Вася»); // Привет, Вася! sayHello(«Здравствуйте»); // Здравствуйте, Гость! sayHello(«Привет»,null); // Привет, !

  1. Откройте предыдущее задание с отрисовкой таблицы в функции. Измените входящие параметры функции gettable() на параметры по умолчанию

Задание 5

  • Отрисуйте таблицу умножения вызывая функцию getTable() без параметров
  • Отрисуйте таблицу умножения вызывая функцию getTable() с одним параметром
  • Отрисуйте таблицу умножения вызывая функцию getTable() с двумя параметрами

    Возвращение значений функцией, Return

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

    Внутри такой функции используется оператор возврата return (с англ. «вернуть»), после которого указывается возвращаемое значение (или переменная, массив, выражение и т.п.)

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

    function sum($a, $b) < return $a + $b; >// 1 вариант вызова echo sum(1, 2) ; // 2 вариант вызова $x=sum(1, 2); echo $x;

    Задание 1

    1. Опишите функцию getMenu()
    2. Задайте для функции первый аргумент menu , в него будет передаваться массив, содержащий структуру меню
    3. Задайте для функции второй аргумент vertical со значением по умолчанию равным TRUE (логический тип данных — true-истина, false-ложь).

    Данный параметр указывает, каким образом будет отрисовано меню — вертикально или горизонтально

    Задание 2

    1. Откройте файл c лабораторной работой с отрисовкой меню
    2. Скопируйте код, который создает массив menu и вставьте скопированный код в данный документ
    3. Скопируйте код, который отрисовывает меню
    4. Вставьте скопированный код в тело функции getMenu()
    5. Измените код таким образом, чтобы меню отрисовывалась в зависимости от входящих параметров menu и vertical


    Задание 3

    1. Отрисуйте вертикальное меню вызывая функцию getMenu() с одним параметром
    2. Отрисуйте горизонтальное меню вызывая функцию getMenu() со вторым параметром равным FALSE
    3. Сохраните код в отдельном файле

    PHP: Определение и вызов функции

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

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

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

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

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

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

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

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

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

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

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

    Функции

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

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

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

    Илон Маск рекомендует:  Что такое код curl_init

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

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

    Вызов встроенных функций PHP

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Рекурсия

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

    Илон Маск рекомендует:  Извлечение из файла строки со случайным номером на PHP

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

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

    Функция func_num_args()

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

    Функция func_get_arg()

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

    Функция func_get_args()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    PHP 5 Функции

    Реальная мощь PHP исходит от его функций; Он имеет более чем 1000 встроенных функций.

    Определяемые пользователем функции PHP

    Помимо встроенных функций PHP, мы можем создавать собственные функции.

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

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

    Функция будет выполнена вызовом функции.

    Создание определяемой пользователем функции в PHP

    Объявление определяемой пользователем функции начинается со слова function :

    Синтаксис

    Примечание: Имя функции может начинаться с буквы или подчеркивания (не числа).

    Совет: Дайте функции имя, которое отражает то, что функция делает!

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

    В приведенном ниже примере мы создаем функцию с именем «вритемсг ()». Открывающая фигурная скобка (<) указывает начало кода функции, а закрывающая фигурная скобка (>) указывает на конец функции. Функция выводит «Hello World!». Чтобы вызвать функцию, просто напишите ее имя:

    Пример

    Аргументы функции PHP

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

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

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

    Пример

    В следующем примере имеется функция с двумя аргументами ($fname и $year):

    Пример

    Значение аргумента по умолчанию PHP

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

    Пример

    PHP функции-возвращаемые значения

    Чтобы позволить функции возвращать значение, используйте инструкцию return :

    Функции (function) на PHP. Урок 10

    2014-09-29 / Вр:01:49 / просмотров: 6895

    Итак, что такое функция (function)на PHP?

    Функция (function)- это мини-программа, которая выполняет какие-то полезные действия и выдает готовый результат.
    Давайте посмотрим на схемку:

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

    Припустим, нам нужно написать функцию, которая сможет подсчитать сумму чисел 5 и 2 . Смотрим на шаблон и пишем:

    Разберем код .
    function suma() — это функция с именем suma ;
    echo 5 + 2; — в теле функции мы указали, что числа 5 и 2 нужно сложить вместе (5 + 2) ;
    suma(); — вызываем функцию. Вызов функции означает ее выполнение. То есть, задачка 5 + 2 должна быть выполнена и дать результат 7 .

    Теперь попробуем рассмотреть функции поэтапно.

    Этапы создания функции на PHP

    Этап I. Создание функции
    Вспомните готовый шаблон функции:

    Вот таким способом создается функция на PHP.
    Давайте в теле функции напишем текст « Я рад видеть вас на блоге bloggood.ru ».
    Только не забудьте: текст пишем через оператор вывода «echo».

    Теперь нужно вызвать функцию « bloggood_ru() ».

    Этап II. Вызов готовой функции на PHP
    Функция создана и теперь она должна быть выполнена. Для выполнения и вывода функции достаточно указать « имя функции(); »

    Это будет выглядеть вот так:

    Можно это сделать и так:

    Сохраните как « function.php » в папку « test-1 » локального сервера (см. урок 1).

    Введите в браузере адрес:

    Функции PHP с аргументами

    Все примеры с функциями выше были без аргументов. Что такое аргумент я вам объясню на коде:

    Итак, я создал функцию с именем « bloggood_ru ». В параметрах (там, где скобки) прописал через запятую две переменные $a и $b .

    function bloggood_ru ( $a , $b )

    $a и $b – это и есть два аргумента.
    echo «$a + $b = «; – здесь я вывел на монитор текст. Результат: 5 + 5 =
    echo $a + $b; – здесь я указал функции, что переменную $a и $b нужно сложить вместе.
    bloggood_ru (15, 5); – вызвал функцию. Внимание: в скобках я указал два аргумента (15, 5) , которые ждет переменная $a и $b . Переменная $a получит первый аргумент – 15 , $b – второй 5 .

    Для тех, кто не понял, куда подставляется аргумент и в какой очередности, вот схема:

    Итак, готовый код:

    Сохраните как « function.php » в папку « test-1 » локального сервера (см. урок 1).

    Введите в браузере адрес:

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

    Разбор вызовов функций в PHP

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


    Обычно применяется метод strlen:

    Однако такой вариант примерно на 20% медленнее этого:

    Выглядит неплохо. Наверняка вы уже собрались открыть ваши исходники и заменить все вызовы strlen() на isset(). Но если внимательно прочитать оригинальную статью, то можно заметить, что причина 20-процентной разницы в производительности — многократные вызовы strlen(), порядка 60-80 тысяч итераций.

    Почему?

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

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

    Есть и ещё один момент: при сравнении производительности strlen() с чем-либо ещё добавляется дополнительный opcode. А в случае с isset() используется лишь один уникальный opcode.

    Пример дизассемблированной структуры if(strlen()):

    А вот семантически эквивалентная структура if(isset()):

    Как видите, в коде isset() не задействуется вызов какой-либо функции (DO_FCALL). Также здесь нет opcode IS_SMALLER (просто проигнорируйте операторы RETURN); isset() напрямую возвращает булево значение; strlen() же сначала возвращает временную переменную, затем она передаётся в opcode IS_SMALLER, а уже финальный результат вычисляется с помощью if(). То есть в структуре strlen() используется два opcode, а в структуре isset() — один. Поэтому isset() демонстрирует более высокую производительность, ведь одна операция выполняется обычно быстрее, чем две.

    Давайте теперь разберёмся, как в PHP работают вызовы функций и чем они отличаются от isset().

    Вызовы функций в PHP

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

    Для начала разберём время выполнения (runtime) вызовов. Во время компиляции (compile time) на выполнение операций, связанных с PHP-функциями, требуется много ресурсов. Но если вы будете использовать кэш opcode, то во время компиляции у вас не будет проблем.

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

    Для понимания механизма вызова функции, необходимо знать две вещи:

    • вызов функции и вызов метода — это одно и то же
    • вызов пользовательской функции и вызов внутренней функции обрабатываются по-разному

    Вот почему в последнем примере говорится о вызове «внутренней» функции: strlen() представляет собой PHP-функцию, являющуюся частью С-кода. Если бы мы сделали дамп opcode «пользовательской» PHP-функции (то есть функции, которая написана на языке PHP), то могли бы получить либо точно такой же, либо какой-то другой opcode.

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

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

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

    Opcode SEND_VAR отвечает за отправку аргументов в стековый кадр. Компилятор в обязательном порядке генерирует такой opcode до вызова функции. Причём для каждой переменной создаётся свой собственный:

    Здесь вы видите ещё один opcode — SEND_VAL. Всего существует 4 вида opcode для отправки чего-либо в стек функции:

    • SEND_VAL: отправляет значение константы (строковое, целочисленное и т.д.)
    • SEND_VAR: отправляет PHP-переменную ($a)
    • SEND_REF: отправляет PHP-переменную в виде ссылки в функцию, которая принимает аргумент ссылкой
    • SEND_VAR_NO_REF: оптимизированный обработчик, применяемый в случаях с вложенными функциями

    Что делает SEND_VAR?

    SEND_VAR проверяет, является ли переменная ссылкой. Если да, то он её отделяет, тем самым создавая несоответствие ссылки. Почему это очень плохо, вы можете почитать в другой моей статье. Затем SEND_VAR добавляет количество ссылок на нее (ссылка здесь – это не ссылка в терминах PHP, то есть не та которая &, а просто показатель того, сколько кто использует это значение) — к переменной и отправляет в стек виртуальной машины:

    Каждый раз, вызывая функцию, вы увеличиваете на единицу refcount каждого переменного аргумента стека. Это происходит потому, что на переменную будет ссылаться не код функции, а её стек. Отправка переменной в стек слабо влияет на производительность, но стек занимает память. Он размещается в ней во время исполнения, но его размер высчитывается во время компиляции. После того как мы отправили в стек переменную, запускаем DO_FCALL. Ниже — пример того, какое количество кода и проверок используется только для того, чтобы мы считали вызовы PHP-функций «медленными» операторами (slow statement):

    Илон Маск рекомендует:  Что такое код windowfrompoint

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

    Далее мы вызываем zend_do_fcall_common_helper(). Я не буду выкладывать здесь код этой функции, он слишком объёмный. Я покажу только те операции, которые там были выполнены. Если вкратце, это множество различных проверок, сделанных во время исполнения. PHP — динамический язык, во время выполнения он может объявлять новые функции и классы, попутно автоматически загружая файлы. Поэтому PHP вынужден проводить во время выполнения множество проверок, что плохо сказывается на производительности. Но от этого никуда не деться.

    Видите, сколько проверок? Идём дальше:

    Вы знаете, что каждое тело функции имеет собственную область видимости переменной. Движок переключает таблицы видимости перед вызовом кода функции, так что если он запросит переменную, то она будет найдена в соответствующей таблице. А поскольку функции и методы по сути одно и то же, можете почитать о том, как забиндить на метод указатель $this.

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

    Приведённая строка вызывает обработчик внутренней функции. В случае с нашим примером относительно strlen() данная строка вызовет код:

    Что делает strlen()? Он извлекает аргумент из стека с помощью zend_parse_parameters(). Это «медленная» функция, потому что ей приходится поднимать стек и конвертировать аргумент в ожидаемый функцией тип (в нашем случае — в строковый). Поэтому независимо от того, что вы передадите в стек для strlen(), ей может понадобиться конвертировать аргумент, а это не самый лёгкий процесс с точки зрения производительности. Исходный код zend_parse_parameters() дает неплохое представление о том, сколько операций приходится выполнить процессору во время извлечения аргументов из стекового кадра функции.

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

    Затем очистим стек:

    И, наконец, если во время выполнения функции были сделаны какие-то исключения, нужно направить виртуальную машину на блок отлова этого исключения:

    О вызовах PHP-функций

    Теперь вы можете представить, сколько времени тратит компьютер на вызов «очень маленькой и простой» функции strlen(). А поскольку она вызывается многократно, увеличьте это время, скажем, в 25 000 раз. Вот так микро- и миллисекунды превращаются в полноценные секунды… Обратите внимание, что я продемонстрировал только самые важные для нас инструкции во время каждого вызова PHP-функции. После этого случается ещё много всего интересного. Также имейте в виду, что в случае с strlen() «полезную работу» выполняет лишь одна строка, а сопутствующие процедуры по подготовке вызова функции по объёму больше, чем «полезная» часть кода. Однако в большинстве случаев собственный код функций всё же больше влияет на производительность, чем «вспомогательный» код движка.

    Та часть кода PHP, которая относится к вызову функций, в PHP 7 была переработана с целью улучшения производительности. Однако это далеко не конец, и исходный код PHP ещё не раз будет оптимизироваться с каждым новым релизом. Не были забыты и более старые версии, вызовы функций были оптимизированы и в версиях от 5.3 до 5.5. Например, в версиях с 5.4 до 5.5 был изменён способ вычисления и создания стекового кадра (с сохранением совместимости). Ради интереса можете сравнить изменения в исполняющем модуле и способе вызова функций, сделанные в версии 5.5 по сравнению с 5.4.

    Хочу подчеркнуть: все вышесказанное не значит, что PHP плох. Этот язык развивается уже 20 лет, над его исходным кодом работало множество очень талантливых программистов. За этот период он много раз перерабатывался, оптимизировался и улучшался. Доказательством этого служит тот факт, что вы сегодня используете PHP и он демонстрирует хорошую общую производительность в самых разных проектах.

    А что насчёт isset()?

    Это не функция, круглые скобки не обязательно означают «вызов функции». isset() включён в специальный opcode виртуальной машины Zend (ISSET_ISEMPTY), который не инициализирует вызов функции и не подвергается связанным с этим задержкам. Поскольку isset() может использовать параметры нескольких типов, его код в виртуальной машине Zend получается довольно длинным. Но если оставить только часть, относящуюся к параметру offset, то получится примерно так:

    Если убрать многочисленные точки принятия решения (конструкции if), то «основной» вычислительный алгоритм можно выразить строкой:

    Если offset больше нуля (вы не имели в виду isset($a[-42])) и строго меньше длины строки, результат будет принят равным 1. Тогда итогом операции будет булево TRUE. Не волнуйтесь насчёт вычисления длины, Z_STRLEN_P(container) ничего не вычисляет. Помните, что PHP уже известна длина вашей строки. Z_STRLEN_P(container) просто считывает это значение в память, на что тратится крайне мало ресурсов процессора.

    Теперь вы понимаете, почему с точки зрения использования смещения строки обработка вызова функции strlen() требует ГОРАЗДО больше вычислительных ресурсов, чем обработка isset(). Последний существенно «легче». Пусть вас не пугает большое количество условных операторов if, это не самая тяжёлая часть С-кода. К тому же их можно оптимизировать с помощью С-компилятора. Код обработчика isset() не ищет в хэш-таблицах, не производит сложных проверок, не присваивает указателя одному из стековых кадров, чтобы позднее достать его. Код гораздо легче, чем общий код вызова функции, и намного реже обращается к памяти (это самый важный момент). И если закольцевать многократное выполнение такой строки, можно добиться большого улучшения производительности. Конечно, результаты одной итерации strlen() и isset() будут мало отличаться — примерно на 5 мс. Но если провести 50 000 итераций…

    Также обратите внимание, что у isset() и empty() практически одинаковый исходный код. В случае со смещением строки empty() будет отличаться от isset() только дополнительным чтением, если первый символ строки не является 0. Поскольку коды empty() и isset() почти не отличаются друг от друга, то empty() будет демонстрировать такую же производительность, что и isset() (учитывая, что оба используются с одинаковыми параметрами).

    Чем нам может быть полезен OPCache

    Если кратко — ничем.

    OPCache оптимизирует код. Об этом можно почитать в презентации. Часто спрашивают, можно ли добавить оптимизационный проход, при котором strlen() переключается в isset(). Нет, это невозможно.

    Оптимизационные проходы OPCache осуществляются в OPArray до того, как он помещается в совместно используемую память. Это происходит во время компиляции, а не во время выполнения. Откуда нам знать во время компиляции, что переменная, которая передаётся в strlen(), является строкой? Это известная проблема PHP, и она отчасти решается с помощью HHVM/Hack. Если бы мы записали в PHP наши переменные со строгой типизацией, то во время проходов компилятора можно было бы оптимизировать гораздо больше вещей (как и в виртуальной машине). Так как PHP является динамическим языком, во время компиляции не известно почти ничего. OPCache может оптимизировать только статические вещи, известные к моменту начала компиляции. Например, вот это:

    Во время компиляции известно, что длина строки «foo» не больше 8, поэтому можно выкинуть все opcode if(), а от конструкции if оставить только часть с else.

    Но что такое $a? Оно вообще существует? Это строка? К моменту прохода оптимизатора мы ещё не можем ответить на все эти вопросы — это задача для исполняющего модуля виртуальной машины. Во время компиляции мы обрабатываем абстрактную структуру, а тип и нужный объём памяти будут известны во время выполнения.

    OPCache оптимизирует многие вещи, но из-за самой природы PHP он не может оптимизировать всё подряд. По крайне мере не столько, сколько в компиляторе Java или С. Увы, PHP никогда не будет языком со строгой типизацией. Также периодически высказываются предложения по введению в декларирование свойств класса указания read-only:

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

    Подсказки по оптимизации и заключительное слово

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

    Вторая подсказка: PHP работает действительно быстро, эффективно и надёжно. Возможностей оптимизации PHP-скриптов не так много — например, их меньше, чем в более низкоуровневых языках вроде С. Поэтому усилия по оптимизации нужно направлять на циклы без конкретных условий на выход из них. Если профайлер покажет узкое место скрипта, вероятнее всего, оно будет внутри цикла. Именно здесь крохотные задержки накапливаются в полновесные секунды, поскольку количество итераций в циклах измеряется десятками тысяч. В PHP такие циклы одинаковы, за исключением foreach(), и ведут к одному и тому же opcode. Менять в них while на for бессмысленно, и профайлер вам это докажет.

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

    Приведённые примеры не всегда полностью эквивалентны, за подробностями обратитесь к документации.

    Да, и старайтесь избегать таких глупостей, как:

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

    Чаще профилируйте свой скрипт и проверяйте каждое предположение, не следуйте слепо чужим инструкциям. Всегда всё проверяйте.

    Разработчики профайлера Blackfire заложили в свой продукт механизм сбора интересных метрик, способных помочь пользователям в их работе. Регистрируется множество параметров (хотя GUI показывает ещё не все): например, когда запускается сборщик мусора, что он делает, сколько объектов создано/уничтожено в функциях, сколько несоответствий ссылок было создано во время вызовов функций, время сериализации, неправильное поведение foreach() и т.д. и т.п.

    Также не забывайте, что в один прекрасный момент вы столкнётесь с ограничениями языка. Возможно, тогда будет целесообразно выбрать какой-то другой. PHP не годится для создания ORM, видеоигр, HTTP-серверов и многих других задач. Его можно для этого использовать, но это будет неэффективно. Так что для каждой задачи лучше выбирать наиболее подходящий язык, благо сегодня есть из чего выбрать: Java, Go или, наверное, самый эффективный язык нашего времени — C/C++ (Java и Go написаны именно на нем).

    Пользовательские функции в PHP

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

    Создание функций

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

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

    Заметьте, функция выполняется только при её вызове. Если убрать из примера выше строку message(); , то функция не запустится.

    Аргументы функций

    Функция может принимать значения от пользователя:

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

    Получение значения из функции

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

    Получить результат вычислений функции можно с помощью оператора return :

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

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

    Значения по-умолчанию

    Вы можете указать значение по-умолчанию для переменной:

    В примере выше мы указываем, что если 2-ой параметр не передан, то переменная получит значение 2 .

    Типы аргументов

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

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

    Тип возвращаемого значения

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

    Функции php

    Из предыдущих уроков вы узнали, что в php есть встроенные функции, например функции обработки строк. На примерах вы могли разобраться, что функция может иметь собственные параметры, которые указываются в скобках. В php есть множество встроенных функций для любых целей, но иногда бывает нужно создать свою функцию. Для этого существует конструкция function. Этот простой пример показывает, как нужно создавать функции. Функция создана и вы можете её использовать. Для этого её неоходимо вызвать, как любую стандартную функцию.
    Этот пример показывает практически все возможности пользовательской функции. Вы можете задавать параметры, например, $a, $b, $c. Эти переменные требуются для работы функции. Последний параметр (или несколько последних), могут быть предворительно заданы(дополнительные). Если при вызове функции не заполнены дополнительные параметры, то функция работает с теми значениями, которые заданы изначально. В теле функции может быть любой код. Затем идет присвоение значения функции. Т.е. функция вернет значение.
    Функция может вернуть массив. Что бы его преобразовать в переменные, можно использовать функцию list:

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

    Если этот сайт оказался вам полезен, пожалуйста, посмотрите другие наши статьи и разделы.

    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL