Глава 1.3: Функции
Создание, параметры, возврат значений, области видимости, анонимные функции
Зачем нужны функции?
Представь, что тебе нужно вычислить площадь прямоугольника в 10 местах программы:
<?php
// ❌ Без функций — копипаста
$area1 = $width1 * $height1;
$area2 = $width2 * $height2;
$area3 = $width3 * $height3;
// ... и так 10 раз
// А если формула изменится? Нужно менять в 10 местах!<?php
// ✅ С функцией — один раз написал, используешь везде
function calculateArea($width, $height) {
return $width * $height;
}
$area1 = calculateArea($width1, $height1);
$area2 = calculateArea($width2, $height2);
$area3 = calculateArea($width3, $height3);
// Изменить формулу? Меняем только в одном месте!Функции дают:
┌─────────────────────────────────────────────────────────────────┐
│ ПРЕИМУЩЕСТВА ФУНКЦИЙ │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 🔄 ПЕРЕИСПОЛЬЗОВАНИЕ │
│ Написал один раз — используешь многократно │
│ │
│ 📦 АБСТРАКЦИЯ │
│ Скрываешь сложность за простым именем │
│ calculateTax() вместо формулы в 10 строк │
│ │
│ 🧪 ТЕСТИРУЕМОСТЬ │
│ Легко проверить: вход → выход │
│ │
│ 📖 ЧИТАЕМОСТЬ │
│ Код рассказывает историю: │
│ validateEmail(), sendNotification(), saveToDatabase() │
│ │
│ 🛠️ ПОДДЕРЖИВАЕМОСТЬ │
│ Баг в логике? Исправь в одном месте │
│ │
└─────────────────────────────────────────────────────────────────┘1. Создание функций
Базовый синтаксис
<?php
function имяФункции(параметры) {
// Тело функции
return результат;
}Простейшая функция
<?php
// Определение функции
function sayHello() {
echo "Привет, мир!";
}
// Вызов функции
sayHello(); // Привет, мир!
sayHello(); // Привет, мир!
sayHello(); // Привет, мир!Правила именования
<?php
// ✅ Правильные имена (camelCase — рекомендуется)
function calculateTotal() {}
function getUserById() {}
function isValidEmail() {}
function sendNotification() {}
// ✅ snake_case тоже допустим
function calculate_total() {}
function get_user_by_id() {}
// ❌ Неправильные имена
function 123start() {} // Нельзя начинать с цифры
function my-function() {} // Нельзя дефис
function calculate total() {} // Нельзя пробелСоглашения об именовании
<?php
// Глаголы для действий
function save() {}
function delete() {}
function update() {}
function create() {}
function send() {}
function validate() {}
// get/set для получения/установки
function getName() {}
function setName($name) {}
// is/has/can для проверок (возвращают bool)
function isActive() {}
function hasPermission() {}
function canEdit() {}
// Описательные имена
function calculateMonthlyPayment() {} // ✅ Понятно
function calc() {} // ❌ НепонятноФункция должна делать одну вещь!
<?php
// ❌ Плохо — функция делает слишком много
function processUser($data) {
// Валидация
if (empty($data['email'])) {
return false;
}
// Сохранение в БД
$db->insert('users', $data);
// Отправка email
mail($data['email'], 'Welcome!', 'Hello!');
// Логирование
file_put_contents('log.txt', 'User created');
return true;
}
// ✅ Хорошо — каждая функция делает одно
function validateUserData($data) {
return !empty($data['email']) && !empty($data['name']);
}
function saveUser($data) {
return $db->insert('users', $data);
}
function sendWelcomeEmail($email) {
return mail($email, 'Welcome!', 'Hello!');
}
function logAction($message) {
file_put_contents('log.txt', $message, FILE_APPEND);
}
// Использование
if (validateUserData($data)) {
saveUser($data);
sendWelcomeEmail($data['email']);
logAction('User created');
}2. Параметры функций
Параметры vs Аргументы
<?php
// параметры (при определении)
// ↓ ↓
function greet($name, $age) {
echo "Привет, $name! Тебе $age лет.";
}
// аргументы (при вызове)
// ↓ ↓
greet("Иван", 25);- Параметры — переменные в определении функции
- Аргументы — значения, передаваемые при вызове
Несколько параметров
<?php
function createFullName($firstName, $lastName, $middleName) {
return "$lastName $firstName $middleName";
}
echo createFullName("Иван", "Петров", "Сергеевич");
// Петров Иван СергеевичПараметры по умолчанию
<?php
function greet($name, $greeting = "Привет") {
return "$greeting, $name!";
}
echo greet("Иван"); // Привет, Иван!
echo greet("Иван", "Здравствуй"); // Здравствуй, Иван!
// Параметры по умолчанию ДОЛЖНЫ идти после обязательных!
// ❌ Неправильно
function wrong($a = 1, $b) {} // $b обязательный после необязательного
// ✅ Правильно
function right($b, $a = 1) {}Именованные аргументы (PHP 8+)
<?php
function createUser($name, $email, $age = null, $role = 'user') {
return [
'name' => $name,
'email' => $email,
'age' => $age,
'role' => $role,
];
}
// Позиционные аргументы — порядок важен
$user1 = createUser("Иван", "ivan@test.com", 25, "admin");
// Именованные аргументы — порядок не важен!
$user2 = createUser(
email: "maria@test.com",
name: "Мария",
role: "editor"
// age пропущен — будет null
);
// Можно смешивать (позиционные должны быть первыми)
$user3 = createUser("Пётр", "peter@test.com", role: "admin");Передача по значению vs по ссылке
<?php
// По умолчанию — передача по ЗНАЧЕНИЮ (копия)
function addOne($num) {
$num = $num + 1;
echo "Внутри функции: $num\n";
}
$x = 5;
addOne($x);
echo "Снаружи: $x\n";
// Внутри функции: 6
// Снаружи: 5 ← Не изменилось!
// Передача по ССЫЛКЕ (& перед параметром)
function addOneByRef(&$num) {
$num = $num + 1;
echo "Внутри функции: $num\n";
}
$x = 5;
addOneByRef($x);
echo "Снаружи: $x\n";
// Внутри функции: 6
// Снаружи: 6 ← Изменилось!Когда использовать ссылки?
<?php
// ✅ Хороший случай — модификация большого массива
function sortByPrice(&$products) {
usort($products, fn($a, $b) => $a['price'] <=> $b['price']);
}
$products = [/* большой массив */];
sortByPrice($products); // Сортирует на месте, без копирования
// ❌ Плохой случай — неочевидное поведение
function calculate(&$a, &$b) {
$a = $a * 2;
$b = $b * 2;
return $a + $b;
}
// Лучше вернуть новые значения, чем менять исходныеСовет: Избегай передачи по ссылке, если можно вернуть результат. Ссылки делают код менее предсказуемым.
Variadic функции (переменное число аргументов)
<?php
// ... (splat operator) — собирает аргументы в массив
function sum(...$numbers) {
$total = 0;
foreach ($numbers as $num) {
$total += $num;
}
return $total;
}
echo sum(1, 2); // 3
echo sum(1, 2, 3, 4, 5); // 15
echo sum(); // 0
// Можно комбинировать с обычными параметрами
function greetAll($greeting, ...$names) {
foreach ($names as $name) {
echo "$greeting, $name!\n";
}
}
greetAll("Привет", "Иван", "Мария", "Пётр");
// Привет, Иван!
// Привет, Мария!
// Привет, Пётр!
// Распаковка массива при вызове
$numbers = [1, 2, 3, 4, 5];
echo sum(...$numbers); // 153. Возврат значений
return — возврат результата
<?php
function add($a, $b) {
return $a + $b; // Возвращает результат и ЗАВЕРШАЕТ функцию
}
$result = add(5, 3);
echo $result; // 8
// Можно использовать результат сразу
echo add(10, 20); // 30
echo add(1, 2) + add(3, 4); // 10return без значения
<?php
function printIfPositive($num) {
if ($num <= 0) {
return; // Ранний выход, возвращает null
}
echo "Число: $num\n";
}
$result = printIfPositive(-5); // Ничего не выведет
var_dump($result); // NULLФункция без return
<?php
function sayHello($name) {
echo "Привет, $name!";
// Нет return — функция возвращает null
}
$result = sayHello("Иван");
var_dump($result); // NULLРанний выход (Early Return)
<?php
// ❌ Глубокая вложенность
function processOrder($order) {
if ($order !== null) {
if ($order['status'] === 'pending') {
if ($order['total'] > 0) {
// Основная логика
return processPayment($order);
} else {
return "Пустой заказ";
}
} else {
return "Неверный статус";
}
} else {
return "Заказ не найден";
}
}
// ✅ Ранний выход — плоский код
function processOrder($order) {
if ($order === null) {
return "Заказ не найден";
}
if ($order['status'] !== 'pending') {
return "Неверный статус";
}
if ($order['total'] <= 0) {
return "Пустой заказ";
}
// Основная логика
return processPayment($order);
}Правило: Проверяй ошибочные случаи в начале и выходи сразу. Основная логика — в конце.
Возврат нескольких значений
<?php
// Способ 1: Массив
function getMinMax($numbers) {
return [
'min' => min($numbers),
'max' => max($numbers),
];
}
$result = getMinMax([3, 1, 4, 1, 5, 9]);
echo "Min: {$result['min']}, Max: {$result['max']}";
// Способ 2: list() / деструктуризация
function divide($a, $b) {
$quotient = intdiv($a, $b);
$remainder = $a % $b;
return [$quotient, $remainder];
}
[$q, $r] = divide(17, 5);
echo "17 / 5 = $q, остаток $r"; // 17 / 5 = 3, остаток 2
// Способ 3: Объект (для сложных случаев)
class Result {
public bool $success;
public mixed $data;
public ?string $error;
}4. Типизация функций (PHP 7+)
Типы параметров
<?php
function greet(string $name): void {
echo "Привет, $name!";
}
greet("Иван"); // ✅ OK
greet(123); // ⚠️ Автоприведение: "123"
// Строгий режим — ошибка при несоответствии типов
declare(strict_types=1);
greet(123); // ❌ TypeError!Типы возврата
<?php
function add(int $a, int $b): int {
return $a + $b;
}
function getUser(int $id): array {
return ['id' => $id, 'name' => 'Test'];
}
function isValid(string $email): bool {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
function save(array $data): void {
// void — функция ничего не возвращает
file_put_contents('data.json', json_encode($data));
}Nullable типы
<?php
// ?тип — может быть этот тип ИЛИ null
function findUser(int $id): ?array {
$user = searchInDb($id);
return $user ?: null; // Может вернуть null
}
// Nullable параметр
function greet(?string $name): string {
return "Привет, " . ($name ?? "Гость") . "!";
}
greet("Иван"); // Привет, Иван!
greet(null); // Привет, Гость!Union типы (PHP 8+)
<?php
// Несколько возможных типов
function processId(int|string $id): void {
if (is_int($id)) {
echo "Числовой ID: $id";
} else {
echo "Строковый ID: $id";
}
}
processId(123); // Числовой ID: 123
processId("abc"); // Строковый ID: abc
// В возвращаемом типе
function findUser(int $id): User|null {
// ...
}
// Или короче (то же самое что |null)
function findUser(int $id): ?User {
// ...
}Mixed тип (PHP 8+)
<?php
// mixed = любой тип (включая null)
function dump(mixed $value): void {
var_dump($value);
}
dump(123);
dump("text");
dump([1, 2, 3]);
dump(null);Таблица типов
┌───────────────┬─────────────────────────────────────────────┐
│ Тип │ Описание │
├───────────────┼─────────────────────────────────────────────┤
│ int │ Целое число │
│ float │ Дробное число │
│ string │ Строка │
│ bool │ true/false │
│ array │ Массив │
│ object │ Любой объект │
│ callable │ Функция/callback │
│ iterable │ Массив или Traversable │
│ mixed │ Любой тип (PHP 8+) │
│ void │ Ничего не возвращает │
│ never │ Никогда не возвращает (exit/throw) PHP 8.1+ │
│ null │ Только null │
│ true/false │ Только true или false (PHP 8.2+) │
│ ClassName │ Объект конкретного класса │
│ ?type │ type или null │
│ type1|type2 │ type1 или type2 (PHP 8+) │
└───────────────┴─────────────────────────────────────────────┘5. Область видимости (Scope)
Локальные переменные
Переменные, созданные внутри функции, видны только внутри неё:
<?php
function test() {
$localVar = "Я локальная";
echo $localVar; // ✅ Работает
}
test();
echo $localVar; // ❌ Ошибка! Переменная не существует снаружиГлобальные переменные
Переменные снаружи функции не видны внутри (по умолчанию):
<?php
$globalVar = "Я глобальная";
function test() {
echo $globalVar; // ❌ Ошибка! Переменная не определена
}
test();Доступ к глобальным переменным: global
<?php
$counter = 0;
function increment() {
global $counter; // Объявляем, что используем глобальную
$counter++;
}
increment();
increment();
increment();
echo $counter; // 3$GLOBALS — суперглобальный массив
<?php
$name = "Иван";
$age = 25;
function showInfo() {
echo $GLOBALS['name'] . ", " . $GLOBALS['age'] . " лет";
}
showInfo(); // Иван, 25 лет⚠️ Почему global — это плохо?
<?php
// ❌ Плохо — зависимость от глобальной переменной
$config = ['debug' => true];
function log($message) {
global $config;
if ($config['debug']) {
echo $message;
}
}
// Проблемы:
// 1. Неочевидная зависимость
// 2. Трудно тестировать
// 3. Трудно переиспользовать
// ✅ Хорошо — передавай зависимости явно
function log($message, $config) {
if ($config['debug']) {
echo $message;
}
}
// Или ещё лучше — передай только нужное
function log($message, bool $debug = false) {
if ($debug) {
echo $message;
}
}Правило: Избегай global. Передавай данные через параметры, возвращай через return.
Статические переменные
Переменная сохраняет значение между вызовами функции:
<?php
function counter() {
static $count = 0; // Инициализируется только один раз!
$count++;
return $count;
}
echo counter(); // 1
echo counter(); // 2
echo counter(); // 3
echo counter(); // 4
// Без static — каждый раз 1
function counterNoStatic() {
$count = 0;
$count++;
return $count;
}
echo counterNoStatic(); // 1
echo counterNoStatic(); // 1 (всегда 1)Практическое применение static
<?php
// Кеширование результата
function getExpensiveData() {
static $cache = null;
if ($cache === null) {
echo "Вычисляем...\n";
$cache = heavyCalculation();
}
return $cache;
}
getExpensiveData(); // Вычисляем... (первый раз)
getExpensiveData(); // (из кеша)
getExpensiveData(); // (из кеша)
// Генератор уникальных ID
function generateId(): int {
static $id = 0;
return ++$id;
}
echo generateId(); // 1
echo generateId(); // 2
echo generateId(); // 36. Анонимные функции (Closures)
Что такое анонимная функция?
Функция без имени, которую можно сохранить в переменную:
<?php
// Обычная функция
function add($a, $b) {
return $a + $b;
}
// Анонимная функция
$add = function($a, $b) {
return $a + $b;
}; // Точка с запятой обязательна!
echo add(2, 3); // 5
echo $add(2, 3); // 5 (вызов через переменную)Зачем нужны анонимные функции?
<?php
// 1. Callback для функций высшего порядка
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];
// Сортировка с кастомным сравнением
usort($numbers, function($a, $b) {
return $b - $a; // По убыванию
});
// [9, 6, 5, 4, 3, 2, 1, 1]
// Фильтрация
$evenNumbers = array_filter($numbers, function($n) {
return $n % 2 === 0;
});
// [6, 4, 2]
// Трансформация
$doubled = array_map(function($n) {
return $n * 2;
}, $numbers);
// [18, 12, 10, 8, 6, 4, 2, 2]Замыкания (Closures) — захват переменных
Анонимная функция может "захватить" переменные из внешней области:
<?php
$multiplier = 3;
// use — захватывает переменные из внешней области
$multiply = function($n) use ($multiplier) {
return $n * $multiplier;
};
echo $multiply(5); // 15
echo $multiply(10); // 30
// Без use — переменная недоступна
$broken = function($n) {
return $n * $multiplier; // ❌ Ошибка! $multiplier не определена
};use по значению vs по ссылке
<?php
$value = 10;
// По значению (копия)
$byValue = function() use ($value) {
return $value;
};
// По ссылке
$byRef = function() use (&$value) {
return $value;
};
echo $byValue(); // 10
echo $byRef(); // 10
$value = 20;
echo $byValue(); // 10 (копия, не изменилась)
echo $byRef(); // 20 (ссылка, отражает изменение)Практический пример: фильтр по порогу
<?php
function createFilter($threshold) {
return function($value) use ($threshold) {
return $value >= $threshold;
};
}
$numbers = [1, 5, 10, 15, 20, 25];
$above10 = createFilter(10);
$above20 = createFilter(20);
$filtered1 = array_filter($numbers, $above10); // [10, 15, 20, 25]
$filtered2 = array_filter($numbers, $above20); // [20, 25]7. Стрелочные функции (PHP 7.4+)
Синтаксис
<?php
// Обычная анонимная функция
$add = function($a, $b) {
return $a + $b;
};
// Стрелочная функция — короче!
$add = fn($a, $b) => $a + $b;
echo $add(2, 3); // 5Особенности стрелочных функций
<?php
// 1. Автоматический захват переменных (без use)
$multiplier = 3;
$multiply = fn($n) => $n * $multiplier; // use не нужен!
echo $multiply(5); // 15
// 2. Только одно выражение (неявный return)
$double = fn($n) => $n * 2;
// ❌ Нельзя несколько строк
$broken = fn($n) => {
$result = $n * 2;
return $result;
};
// 3. Захват всегда по значению (не по ссылке)
$value = 10;
$getValue = fn() => $value;
$value = 20;
echo $getValue(); // 10 (не 20!)Когда использовать
<?php
// ✅ Стрелочные функции — для коротких callback
$numbers = [1, 2, 3, 4, 5];
$doubled = array_map(fn($n) => $n * 2, $numbers);
$even = array_filter($numbers, fn($n) => $n % 2 === 0);
$sum = array_reduce($numbers, fn($carry, $n) => $carry + $n, 0);
// Сортировка
usort($users, fn($a, $b) => $a['age'] <=> $b['age']);
// ✅ Обычные анонимные — для сложной логики
$process = function($item) use ($config, $logger) {
$logger->log("Processing: " . $item['id']);
if (!$this->validate($item)) {
return null;
}
return $this->transform($item, $config);
};8. Функции высшего порядка
Функция, которая принимает функцию как аргумент или возвращает функцию:
array_map — применить функцию к каждому элементу
<?php
$numbers = [1, 2, 3, 4, 5];
// Удвоить каждый элемент
$doubled = array_map(fn($n) => $n * 2, $numbers);
// [2, 4, 6, 8, 10]
// Несколько массивов
$a = [1, 2, 3];
$b = [10, 20, 30];
$sum = array_map(fn($x, $y) => $x + $y, $a, $b);
// [11, 22, 33]
// Без callback — объединение
$result = array_map(null, $a, $b);
// [[1, 10], [2, 20], [3, 30]]array_filter — оставить элементы, прошедшие проверку
<?php
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Только чётные
$even = array_filter($numbers, fn($n) => $n % 2 === 0);
// [2, 4, 6, 8, 10]
// Без callback — убрать falsy значения
$array = [0, 1, '', 'hello', null, [], [1]];
$filtered = array_filter($array);
// [1, 'hello', [1]]
// Фильтр по ключу
$data = ['a' => 1, 'b' => 2, 'c' => 3];
$filtered = array_filter($data, fn($key) => $key !== 'b', ARRAY_FILTER_USE_KEY);
// ['a' => 1, 'c' => 3]
// Фильтр по ключу и значению
$filtered = array_filter($data, fn($val, $key) => $key !== 'b' && $val > 1, ARRAY_FILTER_USE_BOTH);
// ['c' => 3]array_reduce — свернуть массив в одно значение
<?php
$numbers = [1, 2, 3, 4, 5];
// Сумма
$sum = array_reduce($numbers, fn($carry, $n) => $carry + $n, 0);
// 15
// Произведение
$product = array_reduce($numbers, fn($carry, $n) => $carry * $n, 1);
// 120
// Собрать в строку
$words = ['Hello', 'World', 'PHP'];
$sentence = array_reduce($words, fn($carry, $word) => "$carry $word", '');
// " Hello World PHP"
// Сгруппировать
$users = [
['name' => 'Иван', 'role' => 'admin'],
['name' => 'Мария', 'role' => 'user'],
['name' => 'Пётр', 'role' => 'admin'],
];
$grouped = array_reduce($users, function($carry, $user) {
$carry[$user['role']][] = $user['name'];
return $carry;
}, []);
// ['admin' => ['Иван', 'Пётр'], 'user' => ['Мария']]usort — сортировка с callback
<?php
$users = [
['name' => 'Иван', 'age' => 25],
['name' => 'Мария', 'age' => 30],
['name' => 'Пётр', 'age' => 20],
];
// Сортировка по возрасту
usort($users, fn($a, $b) => $a['age'] <=> $b['age']);
// Пётр (20), Иван (25), Мария (30)
// По убыванию
usort($users, fn($a, $b) => $b['age'] <=> $a['age']);
// Мария (30), Иван (25), Пётр (20)
// По имени
usort($users, fn($a, $b) => strcmp($a['name'], $b['name']));
// Иван, Мария, ПётрСоздание своей функции высшего порядка
<?php
// Функция, возвращающая функцию
function multiplier(int $factor): callable {
return fn($n) => $n * $factor;
}
$double = multiplier(2);
$triple = multiplier(3);
echo $double(5); // 10
echo $triple(5); // 15
// Функция, принимающая функцию
function applyTwice(callable $func, $value) {
return $func($func($value));
}
echo applyTwice(fn($n) => $n + 1, 5); // 7 (5+1+1)
echo applyTwice(fn($n) => $n * 2, 3); // 12 (3*2*2)9. Рекурсия
Что такое рекурсия?
Функция вызывает сама себя:
<?php
// Факториал: n! = n * (n-1) * (n-2) * ... * 1
function factorial(int $n): int {
if ($n <= 1) {
return 1; // Базовый случай — остановка рекурсии
}
return $n * factorial($n - 1); // Рекурсивный вызов
}
echo factorial(5); // 120 (5 * 4 * 3 * 2 * 1)
// Как это работает:
// factorial(5)
// → 5 * factorial(4)
// → 5 * 4 * factorial(3)
// → 5 * 4 * 3 * factorial(2)
// → 5 * 4 * 3 * 2 * factorial(1)
// → 5 * 4 * 3 * 2 * 1
// → 120Обязательные компоненты рекурсии
<?php
function recursiveFunction($input) {
// 1. БАЗОВЫЙ СЛУЧАЙ — условие остановки
if (условие_остановки) {
return результат;
}
// 2. РЕКУРСИВНЫЙ СЛУЧАЙ — функция вызывает себя с другими аргументами
return recursiveFunction(изменённый_input);
}⚠️ Без базового случая — бесконечная рекурсия!
Примеры рекурсии
<?php
// Числа Фибоначчи
function fibonacci(int $n): int {
if ($n <= 1) {
return $n;
}
return fibonacci($n - 1) + fibonacci($n - 2);
}
echo fibonacci(10); // 55
// Обход вложенного массива
function sumNestedArray(array $arr): int {
$sum = 0;
foreach ($arr as $item) {
if (is_array($item)) {
$sum += sumNestedArray($item); // Рекурсия для вложенных
} else {
$sum += $item;
}
}
return $sum;
}
$nested = [1, [2, 3], [4, [5, 6]]];
echo sumNestedArray($nested); // 21
// Обход директории
function listFiles(string $dir): array {
$files = [];
foreach (scandir($dir) as $item) {
if ($item === '.' || $item === '..') continue;
$path = "$dir/$item";
if (is_dir($path)) {
$files = array_merge($files, listFiles($path));
} else {
$files[] = $path;
}
}
return $files;
}Когда использовать рекурсию?
✅ Хорошо для:
• Древовидные структуры (DOM, файловая система)
• Вложенные данные (JSON, XML)
• Математические последовательности
• Алгоритмы "разделяй и властвуй"
❌ Плохо для:
• Простых циклов (используй for/foreach)
• Глубокой рекурсии (> 100-1000 уровней — stack overflow)
• Случаев, когда важна производительность10. Встроенные функции PHP
PHP имеет огромное количество встроенных функций. Вот самые важные:
Строковые функции
<?php
$str = " Hello World ";
strlen($str); // 15 (длина)
trim($str); // "Hello World" (убрать пробелы)
strtolower($str); // " hello world "
strtoupper($str); // " HELLO WORLD "
ucfirst("hello"); // "Hello"
ucwords("hello world"); // "Hello World"
str_replace("World", "PHP", $str); // " Hello PHP "
substr($str, 2, 5); // "Hello"
strpos($str, "World"); // 8 (позиция)
explode(" ", trim($str)); // ["Hello", "World"]
implode("-", ["a", "b", "c"]); // "a-b-c"
sprintf("Имя: %s, Возраст: %d", "Иван", 25); // ФорматированиеФункции для массивов
<?php
$arr = [3, 1, 4, 1, 5, 9];
count($arr); // 6
in_array(4, $arr); // true
array_search(4, $arr); // 2 (индекс)
array_key_exists('a', $arr); // false
array_push($arr, 2, 6); // Добавить в конец
array_pop($arr); // Удалить с конца
array_shift($arr); // Удалить с начала
array_unshift($arr, 0); // Добавить в начало
sort($arr); // Сортировка (изменяет массив)
rsort($arr); // Обратная сортировка
array_reverse($arr); // Обратный порядок (новый массив)
array_merge([1, 2], [3, 4]); // [1, 2, 3, 4]
array_unique([1, 1, 2, 2, 3]); // [1, 2, 3]
array_slice($arr, 1, 3); // Вырезать часть
array_splice($arr, 1, 2); // Удалить частьМатематические функции
<?php
abs(-5); // 5
round(3.7); // 4
floor(3.7); // 3
ceil(3.2); // 4
max(1, 2, 3); // 3
min(1, 2, 3); // 1
pow(2, 8); // 256
sqrt(16); // 4
rand(1, 100); // Случайное числоФункции для дат
<?php
time(); // Текущий timestamp
date("Y-m-d H:i:s"); // "2025-01-27 14:30:00"
date("d.m.Y", strtotime("+1 week")); // Через неделю
strtotime("2025-12-31"); // Timestamp из строкиФункции для работы с типами
<?php
gettype($var); // Тип как строка
is_string($var); // Проверка типа
is_array($var);
is_int($var);
is_null($var);
isset($var); // Существует и не null?
empty($var); // Пустой? (false, 0, "", null, [])11. Практические примеры
Пример 1: Валидатор данных
<?php
function validateEmail(string $email): bool {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
function validatePhone(string $phone): bool {
// Только цифры, 10-15 символов
$digits = preg_replace('/\D/', '', $phone);
return strlen($digits) >= 10 && strlen($digits) <= 15;
}
function validateAge(int $age): bool {
return $age >= 0 && $age <= 150;
}
function validateUserData(array $data): array {
$errors = [];
if (empty($data['email']) || !validateEmail($data['email'])) {
$errors['email'] = 'Некорректный email';
}
if (empty($data['phone']) || !validatePhone($data['phone'])) {
$errors['phone'] = 'Некорректный телефон';
}
if (!isset($data['age']) || !validateAge($data['age'])) {
$errors['age'] = 'Некорректный возраст';
}
return $errors;
}
// Использование
$data = [
'email' => 'test@example.com',
'phone' => '+7 (999) 123-45-67',
'age' => 25,
];
$errors = validateUserData($data);
if (empty($errors)) {
echo "Данные валидны!";
} else {
foreach ($errors as $field => $message) {
echo "$field: $message\n";
}
}Пример 2: Форматтер данных
<?php
function formatPrice(float $price, string $currency = '₽'): string {
return number_format($price, 2, ',', ' ') . ' ' . $currency;
}
function formatPhone(string $phone): string {
$digits = preg_replace('/\D/', '', $phone);
if (strlen($digits) === 11 && $digits[0] === '7') {
return sprintf(
'+7 (%s) %s-%s-%s',
substr($digits, 1, 3),
substr($digits, 4, 3),
substr($digits, 7, 2),
substr($digits, 9, 2)
);
}
return $phone;
}
function formatDate(string $date, string $format = 'd.m.Y'): string {
$timestamp = strtotime($date);
return $timestamp ? date($format, $timestamp) : $date;
}
// Использование
echo formatPrice(1234567.89); // 1 234 567,89 ₽
echo formatPhone("79991234567"); // +7 (999) 123-45-67
echo formatDate("2025-01-27"); // 27.01.2025Пример 3: Работа с массивами данных
<?php
function findById(array $items, int $id): ?array {
foreach ($items as $item) {
if ($item['id'] === $id) {
return $item;
}
}
return null;
}
function filterByField(array $items, string $field, mixed $value): array {
return array_filter($items, fn($item) => $item[$field] === $value);
}
function sortByField(array $items, string $field, string $direction = 'asc'): array {
usort($items, function($a, $b) use ($field, $direction) {
$cmp = $a[$field] <=> $b[$field];
return $direction === 'desc' ? -$cmp : $cmp;
});
return $items;
}
function pluck(array $items, string $field): array {
return array_map(fn($item) => $item[$field], $items);
}
// Использование
$users = [
['id' => 1, 'name' => 'Иван', 'age' => 25, 'active' => true],
['id' => 2, 'name' => 'Мария', 'age' => 30, 'active' => false],
['id' => 3, 'name' => 'Пётр', 'age' => 28, 'active' => true],
];
$user = findById($users, 2); // Мария
$active = filterByField($users, 'active', true); // Иван, Пётр
$sorted = sortByField($users, 'age', 'desc'); // Мария, Пётр, Иван
$names = pluck($users, 'name'); // ['Иван', 'Мария', 'Пётр']12. Упражнения
Упражнение 1: Базовые функции (15 минут)
Напиши функции:
<?php
// 1. Функция, которая возвращает приветствие
function greet(string $name, string $greeting = "Привет"): string {
// Твой код
}
echo greet("Иван"); // Привет, Иван!
echo greet("Мария", "Здравствуй"); // Здравствуй, Мария!
// 2. Функция проверки чётности
function isEven(int $n): bool {
// Твой код
}
var_dump(isEven(4)); // true
var_dump(isEven(7)); // false
// 3. Функция вычисления площади круга
function circleArea(float $radius): float {
// Твой код (π * r²)
}
echo circleArea(5); // 78.54...Упражнение 2: Работа с массивами (20 минут)
<?php
$products = [
['name' => 'Яблоки', 'price' => 120, 'quantity' => 5],
['name' => 'Бананы', 'price' => 80, 'quantity' => 3],
['name' => 'Молоко', 'price' => 60, 'quantity' => 2],
['name' => 'Хлеб', 'price' => 40, 'quantity' => 1],
];
// 1. Напиши функцию calculateTotal — сумма (price * quantity) всех товаров
// 2. Напиши функцию findExpensive($products, $minPrice) — товары дороже minPrice
// 3. Напиши функцию formatCart($products) — вернуть строку вида:
// "Яблоки x5 = 600₽, Бананы x3 = 240₽, ..."Упражнение 3: Рекурсия (20 минут)
<?php
// 1. Напиши функцию sumDigits — сумма цифр числа
function sumDigits(int $n): int {
// 123 → 1 + 2 + 3 = 6
// Подсказка: $n % 10 — последняя цифра, $n / 10 — остальные
}
// 2. Напиши функцию isPalindrome — проверка палиндрома
function isPalindrome(string $str): bool {
// "radar" → true, "hello" → false
}
// 3. Напиши функцию flatten — превратить вложенный массив в плоский
function flatten(array $arr): array {
// [1, [2, 3], [4, [5, 6]]] → [1, 2, 3, 4, 5, 6]
}Упражнение 4: Функции высшего порядка (25 минут)
<?php
$transactions = [
['type' => 'income', 'amount' => 5000, 'category' => 'salary'],
['type' => 'expense', 'amount' => 1500, 'category' => 'food'],
['type' => 'expense', 'amount' => 3000, 'category' => 'rent'],
['type' => 'income', 'amount' => 1000, 'category' => 'freelance'],
['type' => 'expense', 'amount' => 500, 'category' => 'food'],
];
// Используя array_filter, array_map, array_reduce:
// 1. Получи все расходы (expense)
// 2. Получи сумму всех доходов
// 3. Получи суммы по категориям: ['food' => 2000, 'rent' => 3000, ...]
// 4. Получи баланс (доходы - расходы)13. Вопросы для самопроверки
Чем отличается параметр от аргумента?
Что произойдёт, если не указать return в функции?
Как передать переменную в функцию по ссылке?
Что делает оператор
...(splat)?Почему использование
global— плохая практика?Чем отличается
staticпеременная от обычной?Как захватить внешнюю переменную в анонимной функции?
В чём разница между
fn() =>иfunction() {}?
14. Частые ошибки
Ошибка 1: Изменение параметра по умолчанию
<?php
// ❌ Мутация дефолтного массива
function addItem($item, $list = []) {
$list[] = $item;
return $list;
}
// Работает корректно в PHP, но плохой паттерн
// В других языках это вызывает баги
// ✅ Лучше
function addItem($item, $list = null) {
$list = $list ?? [];
$list[] = $item;
return $list;
}Ошибка 2: Забыт return
<?php
// ❌ Забыли return
function add($a, $b) {
$result = $a + $b;
// return забыт!
}
$sum = add(2, 3);
echo $sum; // Ничего (null)
// ✅ Не забывай return
function add($a, $b) {
return $a + $b;
}Ошибка 3: Ссылка в foreach без unset
<?php
// ❌ Классическая ошибка
function doubleAll(&$arr) {
foreach ($arr as &$val) {
$val *= 2;
}
// Забыли unset($val)!
}
// ✅ Всегда unset после foreach по ссылке
function doubleAll(&$arr) {
foreach ($arr as &$val) {
$val *= 2;
}
unset($val);
}Ошибка 4: Бесконечная рекурсия
<?php
// ❌ Нет базового случая
function countdown($n) {
echo $n;
countdown($n - 1); // Никогда не остановится!
}
// ✅ Есть базовый случай
function countdown($n) {
if ($n < 0) return; // Базовый случай
echo $n;
countdown($n - 1);
}Резюме главы
┌────────────────────────────────────────────────────────────────┐
│ ЗАПОМНИ ГЛАВНОЕ │
├────────────────────────────────────────────────────────────────┤
│ │
│ СОЗДАНИЕ ФУНКЦИЙ │
│ • function имя(параметры) { return результат; } │
│ • Одна функция — одна задача │
│ • Описательные имена: calculateTotal, validateEmail │
│ │
│ ПАРАМЕТРЫ │
│ • По умолчанию передаются по значению (копия) │
│ • &$param — передача по ссылке (изменяет оригинал) │
│ • ...$args — variadic (переменное число аргументов) │
│ • name: value — именованные аргументы (PHP 8+) │
│ │
│ ВОЗВРАТ │
│ • return завершает функцию и возвращает значение │
│ • Без return функция возвращает null │
│ • Ранний выход — проверяй ошибки в начале │
│ │
│ ОБЛАСТЬ ВИДИМОСТИ │
│ • Локальные переменные видны только внутри функции │
│ • Избегай global — передавай через параметры │
│ • static — сохраняет значение между вызовами │
│ │
│ АНОНИМНЫЕ ФУНКЦИИ │
│ • $fn = function() {} — сохраняется в переменную │
│ • use ($var) — захват внешней переменной │
│ • fn() => — стрелочная функция (PHP 7.4+) │
│ │
│ ФУНКЦИИ ВЫСШЕГО ПОРЯДКА │
│ • array_map — применить к каждому │
│ • array_filter — отфильтровать │
│ • array_reduce — свернуть в одно значение │
│ │
└────────────────────────────────────────────────────────────────┘Следующая глава: Глава 1.4: Массивы глубоко — индексированные, ассоциативные, многомерные, функции для работы с массивами