Есть несколько способов вывести дату в таком формате:
Способ 1: IntlDateFormatter (рекомендуется)
$date = new DateTimeImmutable('2025-01-31');
$formatter = new IntlDateFormatter(
'ru_RU',
IntlDateFormatter::LONG,
IntlDateFormatter::NONE,
null,
null,
'd MMMM Y г.'
);
echo $formatter->format($date); // "31 января 2025 г.
В предыдущей части мы рассмотрели, что такое ZVAL в PHP. В это части более подробно рассмотрим, копирование, ссылки и возможные оптимизации.
Все примеры приведены для php 8.3. Для отладки примеров будем использовать метод xdebug_debug_zval. Для этого должно быть установлено расширение xdebug.
$var = 1;
xdebug_debug_zval('var');
Почему мы используем xdebug_debug_zval() вместо debug_zval_dump()?
Начиная с PHP 8.0, функция debug_zval_dump() перестала отображать критически важную информацию:
Не показывает refcount (счетчик ссылок)
Не отображает is_ref (флаг ссылочности)
В то время как xdebug_debug_zval() продолжает предоставлять полную информацию о внутренней структуре ZVAL:
Примечание: Функция xdebug_debug_zval() всегда показывает значение refcount на 1 больше реального. Это особенность реализации Xdebug — при выводе информации он временно увеличивает счетчик ссылок. В следующих примерах я буду указывать корректные значения refcount (уменьшенные на 1), чтобы отражать реальное состояние переменных.
Это означает, что в памяти хранится только одна копия строки, а все переменные ссылаются на один zval.
7. Измерение потребления памяти
<?php
function test1(): void
{
$data = range(1, 100000);
$memBefore = memory_get_usage();
$copy = $data;
$memAfter = memory_get_usage();
showMemory($memBefore, $memAfter);
}
function test2(): void
{
$data = range(1, 100000);
$memBefore = memory_get_usage();
$copy = $data;
$copy[0] = 1;
$memAfter = memory_get_usage();
showMemory($memBefore, $memAfter);
}
function test3(): void
{
$data = range(1, 100000);
$memBefore = memory_get_usage();
$copy = &$data;
$memAfter = memory_get_usage();
showMemory($memBefore, $memAfter);
}
function test4(): void
{
$data = range(1, 100000);
$memBefore = memory_get_usage();
$copy = &$data;
$copy[0] = 1;
$memAfter = memory_get_usage();
showMemory($memBefore, $memAfter);
}
function showMemory($memBefore, $memAfter): void
{
echo "Память до копирования: {$memBefore} байт\n";
echo "Память после копирования: {$memAfter} байт\n";
echo "Разница: " . ($memAfter - $memBefore) . " байт\n";
}
// 1. Присвоение одного массива другому. Без изменения данных.
test1();
// Память не увеличилась.
// Память до копирования: 2514944 байт
// Память после копирования: 2514944 байт
// Разница: 0 байт
// 2. Присвоение одного массива другому. С изменением данных.
test2();
// В результате память увеличилась в двое, т.к. массив был скопирован.
// Память до копирования: 2514976 байт
// Память после копирования: 4628592 байт
// Разница: 2113616 байт
// 3. Присвовение массива по ссылке, без изменения данных
test3();
// Выделяется память только на ссылку.
// Память до копирования: 2514976 байт
// Память после копирования: 2515008 байт
// Разница: 32 байт
// 4. Присвовение массива по ссылке, с изменением данных
test4();
// Выделяется память только на ссылку.
// Память до копирования: 2514976 байт
// Память после копирования: 2515008 байт
// Разница: 32 байт
Директива declare(strict_types=1) — это мощный инструмент в PHP, который обеспечивает строгую проверку типов данных. В этой статье мы подробно разберём, как правильно использовать strict_types, какие преимущества это даёт и как избежать распространённых ошибок.
Что такое strict_types?
strict_types=1 — это директива, которая включает строгую проверку типов для скалярных значений (int, float, string, bool) в пределах файла, где она объявлена.
<?php
declare(strict_types=1);
function sum(int $a, int $b): int {
return $a + $b;
}
sum("1", "2"); // Вызывает TypeError
Основные преимущества
Предотвращение скрытых ошибок типизации
Улучшение читаемости кода
Более предсказуемое поведение
Лучшая поддержка IDE
Практические примеры
Пример с Doctrine Entity
declare(strict_types=1);
#[ORM\Entity]
class Product {
#[ORM\Column(type: 'integer')]
private int $id;
public function setId(int $id): void {
$this->id = $id; // Ошибка при передаче строки
}
}
Работа с API
declare(strict_types=1);
$data = json_decode($response, true);
processOrder((int)$data['id']); // Явное приведение типа
Важные особенности
Действует только в файле, где объявлен
Не влияет на производительность
Всегда проверяет объекты и массивы
Разрешает null для nullable-типов
Рекомендации по внедрению
Начинать с новых файлов
Постепенно добавлять в существующий код
Использовать вместе с phpstan/psalm
Избегать глобального включения через php.ini
Заключение
Strict Types — это важный инструмент для создания надёжного и поддерживаемого кода на PHP. Его использование особенно важно в современных проектах и при работе с такими фреймворками, как Symfony и Laravel.
Сортировка слиянием — это эффективный алгоритм сортировки, работающий по принципу «разделяй и властвуй». Он обладает стабильностью и гарантированной сложностью O(n log n).
В этой статье мы детально разберём структуру zval в современных версиях PHP, начиная с революционного PHP 7. Вы узнаете, как организовано хранение переменных на низком уровне и какие оптимизации были внедрены.
2.1. Основные компоненты zval
Структура _zval_struct
struct _zval_struct {
zend_value value; // Основное значение (64 бита)
union {
struct {
zend_uchar type; // Тип данных (IS_LONG, IS_STRING и др.)
zend_uchar type_flags; // Флаги поведения типа
zend_uchar const_flags; // Флаги константности
zend_uchar reserved; // Зарезервировано
} v;
uint32_t type_info; // Альтернативное представление
} u1; // 32 бита
union u2 { // 32 бита (служебные данные)
uint32_t next; // Для управления хеш-таблицами
uint32_t cache_slot; // Кеширование
uint32_t lineno; // Номер строки (для ошибок)
uint32_t num_args; // Количество аргументов
uint32_t fe_pos; // Позиция в foreach
// ... другие служебные поля
};
}; // Всего 16 байт
1. Компонент value (zend_value)
Тип
Поле
Размер
Описание
Целое
lval
64 бита
Для типов IS_LONG, IS_BOOL
Дробное
dval
64 бита
Для IS_DOUBLE
Указатель
str
64 бита
Для строк (IS_STRING)
Указатель
arr
64 бита
Для массивов (IS_ARRAY)
2. Компонент u1 (метаданные типа)
type — определяет базовый тип данных (IS_LONG, IS_STRING и др.)
type_flags — дополнительные флаги поведения:
IS_TYPE_REFCOUNTED (требует подсчета ссылок)
IS_TYPE_COPYABLE (поддерживает Copy-On-Write)
IS_TYPE_IMMUTABLE (неизменяемый тип)
const_flags — флаги константности
3. Компонент u2 (служебные данные)
Этот компонент используется для различных оптимизаций:
next — связь элементов в хеш-таблицах
cache_slot — кеширование для быстрого доступа
lineno — отладка (номер строки в исходном коде)
num_args — информация о вызовах функций
Практический пример
// Создание zval с целым числом
zval my_zval;
ZVAL_LONG(&my_zval, 42);
// Доступ к данным
if (Z_TYPE(my_zval) == IS_LONG) {
zend_long value = Z_LVAL(my_zval); // 42
php_printf("Значение: %ld\n", value);
}
Zval (Zend value) — фундаментальная структура данных в ядре PHP, ответственная за хранение и обработку всех переменных. В этой статье мы исследуем её эволюцию, современную реализацию и практическое значение для разработчиков.
Историческая эволюция zval
PHP 5: Первое поколение
24-байтовая структура
Универсальный подсчет ссылок
Высокие накладные расходы
PHP 7: Революция
16 байт (экономия 33%)
Разделение value/type
Оптимизация скаляров
PHP 8: Совершенство
Дополнительные оптимизации
Интеграция с JIT
Улучшенные хеш-таблицы
Структура zval в PHP 8
struct _zval_struct {
zend_value value; // 64-битное значение
union {
struct {
zend_uchar type; // Тип данных
zend_uchar type_flags; // Флаги поведения
zend_uchar const_flags; // Константность
zend_uchar reserved; // Выравнивание
} v;
uint32_t type_info;
} u1;
union u2 {
uint32_t next;
// ... служебные поля
};
}; // Всего 16 байт
Ключевые оптимизации
Отказ от refcount для скаляров — целые числа и булевы значения больше не используют подсчет ссылок
Copy-On-Write — сложные структуры копируются только при модификации
Встроенное кеширование хешей — ускорение операций сравнения строк
Оптимизированные хеш-таблицы — быстрый доступ к элементам массивов
Практическое применение для разработчиков и авторов расширений
Оптимизация потребления памяти
Эффективная работа с переменными
Понимание поведения типов
Пример:
// Создание строки в расширении
zend_string *str = zend_string_init("test", 4, 0);
zval zv;
ZVAL_STR(&zv, str);