Функции и организация кода
25 минЗачем нужны функции?
Функция — это блок кода с именем, который можно вызывать много раз.
Вы уже использовали встроенные функции PHP:
date()— получить датуstrlen()— длина строкиtrim()— убрать пробелыhtmlspecialchars()— экранировать HTML
Теперь научимся создавать свои функции.
Создание функции
<?php
// Объявляем функцию
function sayHello($name) {
return "Привет, $name!";
}
// Вызываем функцию
echo sayHello("Мир"); // Привет, Мир!
echo sayHello("PHP"); // Привет, PHP!
?>
Структура функции
function имя_функции($параметр1, $параметр2 = "значение по умолчанию") {
// Код функции
return $результат;
}
function— ключевое словоимя_функции— любое имя (без пробелов, начинается с буквы)$параметры— входные данные (можно со значениями по умолчанию)return— возвращает результат (необязательно)
Файл с функциями-помощниками
Создайте файл public/includes/helpers.php:
<?php
declare(strict_types=1);
/**
* Файл с вспомогательными функциями
*/
/**
* Безопасный вывод текста
* Защищает от XSS-атак
*/
function escape(string $text): string {
return htmlspecialchars($text, ENT_QUOTES, "UTF-8");
}
/**
* Форматирование даты на русском
* Вход: "2024-01-15"
* Выход: "15 января 2024"
*/
function formatDate(string $date): string {
$months = [
1 => "января", 2 => "февраля", 3 => "марта",
4 => "апреля", 5 => "мая", 6 => "июня",
7 => "июля", 8 => "августа", 9 => "сентября",
10 => "октября", 11 => "ноября", 12 => "декабря"
];
$timestamp = strtotime($date);
$day = date("j", $timestamp);
$month = $months[(int)date("n", $timestamp)];
$year = date("Y", $timestamp);
return "$day $month $year";
}
/**
* Обрезка текста до указанной длины
* Не обрезает слова посередине
*/
function truncate(string $text, int $length = 100): string {
if (strlen($text) <= $length) {
return $text;
}
$text = substr($text, 0, $length);
$text = substr($text, 0, strrpos($text, " "));
return $text . "...";
}
/**
* Проверка, является ли текущая страница указанной
* Полезно для выделения активного пункта меню
*/
function isCurrentPage(string $page): bool {
$current = basename($_SERVER["PHP_SELF"]);
return $current === $page;
}
/**
* Генерация класса для пункта меню
*/
function menuClass(string $page): string {
return isCurrentPage($page) ? "active" : "";
}
/**
* Склонение слов (1 комментарий, 2 комментария, 5 комментариев)
*/
function pluralize(int $number, string $one, string $two, string $five): string {
$n = abs($number) % 100;
$n1 = $n % 10;
if ($n > 10 && $n < 20) {
return $five;
}
if ($n1 > 1 && $n1 < 5) {
return $two;
}
if ($n1 == 1) {
return $one;
}
return $five;
}
/**
* Форматирование числа с окончанием
* Пример: formatCount(5, "комментарий", "комментария", "комментариев")
* Результат: "5 комментариев"
*/
function formatCount(int $number, string $one, string $two, string $five): string {
return $number . " " . pluralize($number, $one, $two, $five);
}
?>
Подключаем helpers.php
Обновите includes/config.php:
<?php
declare(strict_types=1);
// Настройки сайта
$site_name = "Мой блог";
$site_description = "Блог о веб-разработке";
$current_year = date("Y");
// Подключаем функции-помощники
require_once __DIR__ . "/helpers.php";
?>
declare(strict_types=1);?Это директива, которая включает строгую проверку типов в PHP. Теперь PHP не будет автоматически преобразовывать типы (например, строку "123" в число 123), что помогает избежать ошибок и делает код более предсказуемым. В PHP 8.4 это обязательная практика!
__DIR__ — магическая константа PHP, содержащая путь к папке текущего файла.Это надёжнее, чем относительный путь, потому что работает из любого места.
Используем функции
Обновите public/index.php:
<?php
require_once "includes/config.php";
$page_title = "Главная — $site_name";
include "includes/header.php";
?>
<h2>Добро пожаловать!</h2>
<p><?= escape($site_description) ?></p>
<h3>Последние посты</h3>
<?php
$posts = [
[
"title" => "Привет, мир!",
"content" => "Это мой первый пост в блоге. Здесь будет много интересного о веб-разработке и программировании на PHP.",
"date" => "2024-01-15",
"comments" => 5
],
[
"title" => "Изучаю PHP",
"content" => "Сегодня я узнал как работать с функциями. Функции делают код чище и понятнее.",
"date" => "2024-01-16",
"comments" => 12
],
[
"title" => "Docker — это круто",
"content" => "Docker сильно упрощает настройку окружения для разработки. Рекомендую всем!",
"date" => "2024-01-17",
"comments" => 0
],
];
?>
<?php foreach ($posts as $post): ?>
<article style="background: #f9f9f9; padding: 20px; margin: 15px 0; border-radius: 8px;">
<h4 style="margin-bottom: 10px;"><?= escape($post["title"]) ?></h4>
<small style="color: #888;">
<?= formatDate($post["date"]) ?> •
<?= formatCount($post["comments"], "комментарий", "комментария", "комментариев") ?>
</small>
<p style="margin-top: 10px;"><?= truncate(escape($post["content"]), 80) ?></p>
</article>
<?php endforeach; ?>
<?php include "includes/footer.php"; ?>
Обновите меню с активным пунктом
В includes/header.php замените меню:
<nav>
<a href="index.php" class="<?= menuClass("index.php") ?>">Главная</a>
<a href="about.php" class="<?= menuClass("about.php") ?>">О нас</a>
<a href="feedback.php" class="<?= menuClass("feedback.php") ?>">Обратная связь</a>
</nav>
И добавьте стиль для активного пункта:
nav a.active {
font-weight: bold;
text-decoration: underline;
}
Результат
Откройте http://localhost:8080. Теперь вы видите:
- Даты на русском языке
- Правильное склонение "комментариев"
- Обрезанный текст с многоточием
- Подсвеченный активный пункт меню
Современные возможности PHP 8+
PHP 8 добавил множество удобных функций. Вот самые полезные:
Строковые функции
<?php
// str_starts_with и str_ends_with — проверка начала/конца строки
$email = "user@example.com";
// Раньше (громоздко):
if (substr($email, 0, 5) === "user@") { }
if (substr($email, -4) === ".com") { }
// PHP 8+ (читаемо!):
if (str_starts_with($email, "user@")) { }
if (str_ends_with($email, ".com")) { }
// str_contains — проверка подстроки
$text = "Привет, мир!";
// Раньше:
if (strpos($text, "мир") !== false) { }
// PHP 8+:
if (str_contains($text, "мир")) { }
?>
Оператор Nullsafe (?->)
<?php
// Раньше (много проверок):
$country = null;
if ($user !== null) {
if ($user->address !== null) {
$country = $user->address->country;
}
}
// PHP 8+ (одна строка!):
$country = $user?->address?->country;
// Если что-то равно null, вернётся null без ошибки
?>
Named Arguments (именованные аргументы)
<?php
// Раньше — нужно помнить порядок аргументов:
htmlspecialchars($text, ENT_QUOTES, "UTF-8", false);
// PHP 8+ — можно указать по имени:
htmlspecialchars($text, encoding: "UTF-8", double_encode: false);
// Или наша функция:
function createUser(string $name, string $email, bool $isAdmin = false, bool $isActive = true) {
// ...
}
// Вызов с именованными аргументами:
createUser(name: "Иван", email: "ivan@example.com", isAdmin: true);
?>
Match expression (вместо switch)
<?php
// switch (громоздко):
switch ($status) {
case "draft": $label = "Черновик"; break;
case "published": $label = "Опубликовано"; break;
case "archived": $label = "В архиве"; break;
default: $label = "Неизвестно";
}
// PHP 8+ match (компактно):
$label = match($status) {
"draft" => "Черновик",
"published" => "Опубликовано",
"archived" => "В архиве",
default => "Неизвестно",
};
?>
Обновим функцию truncate для поддержки Unicode:
/**
* Обрезка текста (с поддержкой Unicode!)
*/
function truncate(string $text, int $length = 100): string {
if (mb_strlen($text) <= $length) {
return $text;
}
$text = mb_substr($text, 0, $length);
$lastSpace = mb_strrpos($text, " ");
if ($lastSpace !== false) {
$text = mb_substr($text, 0, $lastSpace);
}
return $text . "...";
}
Функции mb_* корректно работают с русским текстом (и любым Unicode).
Принципы написания функций
- Одна функция — одна задача. Не делайте функции, которые делают слишком много.
- Понятные имена.
formatDateпонятнее чемfd. - Документация. Комментарии с описанием что функция делает.
- Возвращайте значение, а не выводите через
echo. - Используйте PHP 8+ функции — они делают код чище и понятнее.
Вы научились:
✅ Работать с PHP в реальных файлах
✅ Разделять код на файлы
✅ Обрабатывать формы
✅ Создавать свои функции
В следующем модуле подключим базу данных MySQL!