Акции и промокоды Отзывы о школах

Функции в PHP: что это такое, как работают и как писать правильно

#Блог

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

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

Простая схема работы функции


Функция работает как «черный ящик»: она принимает данные на вход (аргументы), выполняет с ними определенные действия (логика) и возвращает результат.

Объявление и вызов пользовательских функций

В PHP существует два типа блоков кода: встроенные и пользовательские. Встроенные уже написаны создателями языка — например, sort() для сортировки массивов или strlen() для подсчёта длины строки. Пользовательские мы создаём сами под конкретные задачи нашего проекта.

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

<?php
function имяФункции() {
    // тело функции
    // здесь размещается код, который будет выполняться
}

Вызов функции осуществляется простым указанием её имени с круглыми скобками: имяФункции();

Рассмотрим простейший пример:

<?php
function приветствие() {
    echo "Добро пожаловать на наш сайт!";
}

приветствие(); // выведет: Добро пожаловать на наш сайт!

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

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

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

Пример с одним аргументом:

<?php
function приветствиеПользователя($имя) {
    echo "Здравствуйте, " . $имя . "!";
}

приветствиеПользователя("Алексей"); // выведет: Здравствуйте, Алексей!

Функция может принимать несколько аргументов, разделённых запятыми:

<?php
function вычислитьСумму($a, $b) {
    echo $a + $b;
}

вычислитьСумму(5, 3); // выведет: 8

PHP позволяет задавать значения по умолчанию для аргументов. Если при вызове аргумент не передан, будет использовано значение по умолчанию:

<?php
function приветствие($имя = "Гость") {
    echo "Привет, " . $имя . "!";
}

приветствие(); // выведет: Привет, Гость!
приветствие("Мария"); // выведет: Привет, Мария!

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

Возврат значений

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

Пример возврата числа:

<?php
function умножить($x, $y) {
    return $x * $y;
}

$результат = умножить(4, 5);
echo $результат; // выведет: 20

Функция может возвращать строки:

<?php
function полноеИмя($имя, $фамилия) {
    return $имя . " " . $фамилия;
}

echo полноеИмя("Иван", "Петров"); // выведет: Иван Петров

Или даже массивы:

<?php
function получитьКоординаты() {
    return [55.7558, 37.6173]; // широта и долгота Москвы
}

$координаты = получитьКоординаты();
echo $координаты[0]; // выведет: 55.7558

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

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

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

Схема областей видимости переменных в PHP.


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

Локальные переменные

Локальные переменные — это те, которые объявлены внутри функции. Они существуют только во время выполнения и недоступны за её пределами.

<?php
function вычислитьСкидку() {
    $процент = 15; // локальная переменная
    $скидка = 1000 * ($процент / 100);
    return $скидка;
}

echo вычислитьСкидку(); // выведет: 150
echo $процент; // ошибка: переменная $процент не определена

В этом примере переменная $процент существует только внутри функции вычислитьСкидку(). Попытка обратиться к ней извне приведёт к ошибке. Такая изоляция защищает от непреднамеренного изменения данных и конфликтов имён.

Глобальные переменные и ключевое слово global

Иногда возникает необходимость получить доступ к переменной, определённой в глобальной области видимости. Для этого используется ключевое слово global:

<?php
$налоговаяСтавка = 0.2;

function рассчитатьЦенуСНалогом($цена) {
    global $налоговаяСтавка;
    return $цена * (1 + $налоговаяСтавка);
}

echo рассчитатьЦенуСНалогом(100); // выведет: 120

Альтернативный способ — использование суперглобального массива $GLOBALS:

<?php
$налоговаяСтавка = 0.2;

function рассчитатьЦенуСНалогом($цена) {
    return $цена * (1 + $GLOBALS['налоговаяСтавка']);
}

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

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

<?php
function рассчитатьЦенуСНалогом($цена, $ставка) {
    return $цена * (1 + $ставка);
}

echo рассчитатьЦенуСНалогом(100, 0.2); // выведет: 120

Статические переменные

Статические переменные занимают промежуточное положение между локальными и глобальными. Они объявляются внутри функции с ключевым словом static и сохраняют своё значение между вызовами функции:

<?php
function счётчикВызовов() {
    static $счёт = 0;
    $счёт++;
    return $счёт;
}

echo счётчикВызовов(); // выведет: 1
echo счётчикВызовов(); // выведет: 2
echo счётчикВызовов(); // выведет: 3

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

Сравнительная таблица типов переменных:

Тип переменной Область видимости Время жизни Использование
Локальная Внутри функции До конца выполнения функции Для временных вычислений
Глобальная Вся программа До конца выполнения скрипта Не рекомендуется
Статическая Внутри функции До конца выполнения скрипта Для сохранения состояния между вызовами

Понимание этих различий критически важно для написания предсказуемого и надёжного кода. Неправильное использование областей видимости — одна из наиболее распространённых причин ошибок в PHP-приложениях.

Анонимные функции и замыкания

Это функции без имени, которые могут быть присвоены переменным или переданы в качестве аргументов другим блокам кода. Появившись в PHP 5.3, они стали мощным инструментом для написания более гибкого и выразительного кода.

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

<?php
$приветствие = function($имя) {
    return "Здравствуйте, " . $имя . "!";
};

echo $приветствие("Анна"); // выведет: Здравствуйте, Анна!

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

Анонимные  особенно полезны при работе с функциями, которые принимают callback в качестве аргумента. Классический пример — array_map():

<?php
$числа = [1, 2, 3, 4, 5];

$квадраты = array_map(function($число) {
    return $число * $число;
}, $числа);

print_r($квадраты); // выведет: Array([0] => 1 [1] => 4 [2] => 9 [3] => 16 [4] => 25)

 

Одна из наиболее мощных особенностей анонимок — возможность захватывать переменные из родительской области видимости с помощью конструкции use:

<?php
$множитель = 3;

$умножить = function($число) use ($множитель) {
    return $число * $множитель;
};

echo $умножить(5); // выведет: 15

Важный момент: переменные, захваченные через use, копируются по значению в момент создания замыкания. Это означает, что изменения исходной переменной не повлияют на захваченную копию:

<?php
$счётчик = 10;

$функция = function() use ($счётчик) {
    return $счётчик;
};

$счётчик = 20;

echo $функция(); // выведет: 10, а не 20

 

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

<?php
$сумма = 0;

$добавить = function($число) use (&$сумма) {
    $сумма += $число;
};

$добавить(5);
$добавить(10);

echo $сумма; // выведет: 15

 

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

<?php
function создатьУмножитель($множитель) {
    return function($число) use ($множитель) {
        return $число * $множитель;
    };
}

$удвоить = создатьУмножитель(2);
$утроить = создатьУмножитель(3);

echo $удвоить(5);  // выведет: 10
echo $утроить(5);  // выведет: 15

 

Такой подход позволяет создавать функции с предустановленной конфигурацией, что особенно полезно при построении гибких API или реализации паттернов проектирования, таких как Strategy или Factory.

Callback-функции и высшего порядка

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

PHP предоставляет множество встроенных функций, работающих с callback. Рассмотрим наиболее распространённые примеры.

array_map() применяет callback к каждому элементу массива:

<?php
$цены = [100, 250, 450];

$ценыСНалогом = array_map(function($цена) {
    return $цена * 1.2; // добавляем 20% налога
}, $цены);

print_r($ценыСНалогом); // выведет: Array([0] => 120 [1] => 300 [2] => 540)
Схема работы функции array_map


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

array_filter() отбирает элементы массива по заданному условию:

<?php
$числа = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

$чётные = array_filter($числа, function($число) {
    return $число % 2 === 0;
});

print_r($чётные); // выведет: Array([1] => 2 [3] => 4 [5] => 6 [7] => 8 [9] => 10)

usort() сортирует массив с использованием пользовательской логики сравнения:

<?php
$продукты = [
    ['название' => 'Ноутбук', 'цена' => 50000],
    ['название' => 'Мышь', 'цена' => 500],
    ['название' => 'Клавиатура', 'цена' => 2000]
];

usort($продукты, function($a, $b) {
    return $a['цена'] <=> $b['цена']; // сортировка по возрастанию цены
});

print_r($продукты);

 

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

<?php
function удвоить($число) {
    return $число * 2;
}

$результат = array_map('удвоить', [1, 2, 3]);
print_r($результат); // выведет: Array([0] => 2 [1] => 4 [2] => 6)

Для методов классов используется массив с объектом и именем метода:

<?php
class Калькулятор {
    public function квадрат($число) {
        return $число * $число;
    }
}

$calc = new Калькулятор();
$результат = array_map([$calc, 'квадрат'], [2, 3, 4]);
print_r($результат); // выведет: Array([0] => 4 [1] => 9 [2] => 16)

Типичные ошибки при работе с callback:

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

<?php
// Ошибка: функция не существует
$результат = array_map('несуществующаяФункция', [1, 2, 3]);
// Warning: array_map(): Argument #1 should be a valid callback

Другая частая проблема — неправильное указание метода класса:

<?php
// Неверно: передаём строку вместо массива
$результат = array_map('$calc->квадрат', [1, 2, 3]); // не сработает

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

Стрелочные функции в PHP (fn)

Начиная с PHP 7.4, в языке появился более лаконичный синтаксис для создания анонимных функций — стрелочные (arrow functions). Они объявляются с помощью ключевого слова fn и предназначены для написания коротких однострочных функций.

Базовый синтаксис:

<?php
$удвоить = fn($число) => $число * 2;

echo $удвоить(5); // выведет: 10

Сравним анонимную и её стрелочный эквивалент:

<?php
// Традиционная анонимная функция
$квадрат1 = function($x) {
    return $x * $x;
};

// Стрелочная функция
$квадрат2 = fn($x) => $x * $x;

Как видим, стрелочная значительно короче и читается более естественно.

Ключевые отличия от обычных анонимных:

  1. Однострочность: стрелочные могут содержать только одно выражение, которое автоматически возвращается (ключевое слово return не требуется).
  2. Автоматический захват переменных: в отличие от обычных анонимных функций, где нужно явно указывать use, стрелочные автоматически получают доступ ко всем переменным из родительской области видимости:
<?php
$коэффициент = 10;

// С обычной анонимной функцией
$умножить1 = function($число) use ($коэффициент) {
    return $число * $коэффициент;
};

// Со стрелочной функцией
$умножить2 = fn($число) => $число * $коэффициент;

Стрелочные особенно удобны при работе с функциями высшего порядка, такими как array_map:

<?php
$цены = [100, 200, 300];
$налог = 1.15;

// Добавляем налог ко всем ценам
$итоговыеЦены = array_map(fn($цена) => $цена * $налог, $цены);

print_r($итоговыеЦены); // выведет: Array([0] => 115 [1] => 230 [2] => 345)

Или при фильтрации массивов:

<?php
$продукты = [
    ['название' => 'Телефон', 'цена' => 30000],
    ['название' => 'Чехол', 'цена' => 500],
    ['название' => 'Наушники', 'цена' => 3000]
];

$дорогие = array_filter($продукты, fn($товар) => $товар['цена'] > 2000);

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

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

First class callable синтаксис (PHP 8.1+)

PHP 8.1 принёс в язык ещё одно синтаксическое улучшение — first class callable синтаксис. Эта возможность позволяет создавать ссылки на функции и методы как на объекты первого класса, используя оператор … (три точки).

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

<?php
// Старый способ
$длинаСтроки = 'strlen';
$результат = array_map($длинаСтроки, ['Hello', 'World']);

// Или с помощью замыкания
$длинаСтроки = fn($str) => strlen($str);

Новый синтаксис делает код значительно чище:

<?php
$длинаСтроки = strlen(...);

$результат = array_map($длинаСтроки, ['Hello', 'World']);
print_r($результат); // выведет: Array([0] => 5 [1] => 5)

Этот подход работает не только с глобальными функциями, но и с методами объектов:

<?php
class Форматтер {
    public function вВерхнийРегистр($текст) {
        return strtoupper($текст);
    }
}

$форматтер = new Форматтер();
$преобразователь = $форматтер->вВерхнийРегистр(...);

echo $преобразователь('привет'); // выведет: ПРИВЕТ

А также со статическими методами:

<?php
class Математика {
    public static function абсолютноеЗначение($число) {
        return abs($число);
    }
}

$абс = Математика::абсолютноеЗначение(...);
echo $абс(-15); // выведет: 15

Преимущество этого синтаксиса становится особенно очевидным при работе с цепочками вызовов функций высшего порядка:

<?php
$данные = ['  hello  ', '  world  ', '  php  '];

$результат = array_map(
    strtoupper(...),
    array_map(trim(...), $данные)
);

print_r($результат); // выведет: Array([0] => HELLO [1] => WORLD [2] => PHP)

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

Класс Closure и управление контекстом

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

Убедиться в том, что анонимная является объектом Closure, можно следующим образом:

<?php
$функция = function() {
    return "Привет!";
};

var_dump($функция instanceof Closure); // выведет: bool(true)

Метод bindTo() позволяет привязать замыкание к конкретному объекту, изменив его контекст выполнения (то есть значение $this внутри функции):

<?php
class Пользователь {
    private $имя = "Алексей";
}

$получитьИмя = function() {
    return $this->имя;
};

$пользователь = new Пользователь();
$связаннаяФункция = $получитьИмя->bindTo($пользователь, Пользователь::class);

echo $связаннаяФункция(); // выведет: Алексей

Обратите внимание на второй аргумент bindTo() — это область видимости класса. Она необходима для доступа к приватным и защищённым свойствам объекта. Без указания области видимости доступ к приватным членам был бы невозможен.

Метод call() (появился в PHP 7.0) предоставляет более элегантный способ временно привязать замыкание к объекту и сразу же вызвать его:

<?php
class Продукт {
    private $цена = 1000;
}

$получитьЦенуСНалогом = function($ставка) {
    return $this->цена * (1 + $ставка);
};

$продукт = new Продукт();
echo $получитьЦенуСНалогом->call($продукт, 0.2); // выведет: 1200

 

Статический метод bind() работает аналогично bindTo(), но возвращает новое замыкание вместо модификации существующего:

<?php
class Счёт {
    private $баланс = 5000;
}

$проверитьБаланс = function() {
    return $this->баланс;
};

$счёт = new Счёт();
$новаяФункция = Closure::bind($проверитьБаланс, $счёт, Счёт::class);

echo $новаяФункция(); // выведет: 5000

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

Управление контекстом особенно полезно при реализации паттернов проектирования, тестировании приватных методов или создании DSL (domain-specific language). Например, в популярных PHP-фреймворках эти механизмы используются для внедрения зависимостей в замыкания или для создания гибких конфигурационных систем:

<?php
class Конфигуратор {
    private $настройки = [];
   
    public function настроить(Closure $конфиг) {
        $конфиг->call($this);
    }
   
    private function установить($ключ, $значение) {
        $this->настройки[$ключ] = $значение;
    }
}

$конфигуратор = new Конфигуратор();

$конфигуратор->настроить(function() {
    $this->установить('база_данных', 'mysql');
    $this->установить('хост', 'localhost');
});

 

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

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

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

Придерживайтесь читаемых и говорящих имён

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

<?php
// Плохо
function calc($a, $b) { ... }

// Хорошо
function рассчитатьИтоговуюСтоимость($цена, $количество) { ... }

 

Не делайте функции слишком большими

Если она превышает 20-30 строк или выполняет несколько логически различных задач, стоит разбить её на более мелкие части. Принцип единственной ответственности (Single Responsibility Principle) актуален не только для классов:

<?php
// Плохо: функция делает слишком много
function обработатьЗаказ($заказ) {
    // валидация данных
    // расчёт стоимости
    // сохранение в базу
    // отправка email
    // логирование
}

// Хорошо: каждая функция решает одну задачу
function валидироватьЗаказ($заказ) { ... }
function рассчитатьСтоимостьЗаказа($заказ) { ... }
function сохранитьЗаказ($заказ) { ... }

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

<?php
// Плохо: функция неожиданно модифицирует массив
function получитьПервыйЭлемент(&$массив) {
    return array_shift($массив); // изменяет оригинальный массив
}

// Хорошо: функция не имеет побочных эффектов
function получитьПервыйЭлемент($массив) {
    return $массив[0] ?? null;
}

Используйте типизацию аргументов и возвращаемых значений

Начиная с PHP 7.0, язык поддерживает объявление типов, что значительно повышает надёжность кода и помогает избежать ошибок:

<?php
function рассчитатьСкидку(float $цена, int $процент): float {
    return $цена * ($процент / 100);
}

С PHP 8.0 появились union types и mixed type, что делает типизацию ещё более гибкой:

<?php
function обработатьДанные(string|array $данные): mixed {
    // логика обработки
}

Список «Что НЕ делать с функциями»:

❌ Не используйте глобальные переменные без крайней необходимости

❌ Не создавайте функции с более чем 3-4 аргументами (используйте объекты или массивы для группировки параметров)

❌ Не возвращайте разные типы данных в зависимости от условий (например, false при ошибке и массив при успехе)

❌ Не модифицируйте входные параметры без явного указания (используйте & только когда это действительно необходимо)

❌ Не игнорируйте ошибки молча — используйте исключения или возвращайте явные индикаторы ошибок

❌ Не смешивайте уровни абстракции внутри одной функции (например, работа с базой данных и форматирование HTML)

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

 виды функций


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

Заключение

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

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

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

Читайте также
lean-canvas-chto-eto
#Блог

Lean Canvas: что это и как использовать

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

Категории курсов